-
Notifications
You must be signed in to change notification settings - Fork 0
Reduce special cases involving the void type #43
Comments
|
Commit microvm/uvm-hol@eced7b4 deals with the Things that should still be forbidden above. Note that we don't need to explicitly forbid |
The other proposal #45 which allows zero or more return values will undo this change. Then we will have a real "unit" value: 0-tuple. Then:
Then
|
Good point! Getting rid of |
@mn200 Good idea. Alternatively we can make "the whole hybrid" as a counterpart of a C99 struct where the last field is a "flexible array element" ( Obviously Then we can also write Then |
Are irefs allowed to point one past the end of an object? Then even a zero length variable part won't cause a failure for GETVARPARTIREF. |
Out-of-bound irefs are currently not allowed. Worried that the GC may not be able to trace out-of-bound irefs correctly. @eliotmoss mentioned it may be useful for some languages where array indices are not 0-based, but something like 100..200. This has some implications on the GC that the GC must keep track of the object reference even if the iref points out of it. It is easy to implement with fat pointers, but @steveblackburn has some very strong opinion against them. |
The current status
The
void
type is a special type in the Mu type system. It has no value, and thus many instructions/mechanisms have special cases for thevoid
type.Instructions that have special cases for
void
:RET
andRETVOID
: Sincevoid
has no value (In fact it does. The return value of theBRANCH
instruction, for example, is a value of thevoid
type.), we needed a special syntax to returnvoid
, thus we haveRETVOID
.SWAPSTACK
instruction:PASS_VALUE <T> %val
andPASS_VOID
: for the same reason why we haveRET
andRETVOID
.The trap handler has a special case for
void
:Just like
SWAPSTACK
, the trap handler may rebind the thread to a stack and either "pass a value" or "passvoid
" or "throw an exception".Other existing uses
Instructions that always return
void
:BRAHCN
,BRANCH2
,SELECT
,TAILCALL
,RET
,RETVOID
,THROW
,STORE
,FENCE
, some common instructions:@uvm.kill_stack
,@uvm.thread_exit
,@uvm.native.unpin
,@uvm.native.unexpose
,@uvm.meta.load_bundle
,@uvm.meta.load_hail
,@uvm.meta.pop_frame
,@uvm.meta.push_frame
,@uvm.meta.enable_watchpoint
,@uvm.meta.disable_watchpoint
,@uvm.meta.set_trap_handler
: These instructions do not return meaningful values.Instructions that may return
void
sometimes:CALL
,TRAP
,WATCHPOINT
,CCALL
,SWAP_STACK
: The callee, client, swappee, or whatever the other end of communication is, may not return meaningful values.Current properties of
void
void
can only be used in 3 cases:NEW <@void>
. Each time you NEW a void, you have a new empty object, not the same as any other.hybrid<void int<64>>
is a variable-length array ofint<64>
, without a fixed part.BRANCH
instruction returnsvoid
.Other properties:
void
has no value (in fact it does, as mentioned before)void
is neither a scalar type nor a composite type.LOAD
,STORE
, ...void
is nether storable nor loadable. It does not contain other parts. It cannot be part of a struct/array/vector. i.e. there is no "array of void". The "fixed part of a hybrid" is an exception.void
is native-safe: It can be returned from native functions; and there can beuptr<void>
.Proposed changes
value of
void
: Instead of "having no value",void
now has exactly one value: NULL. This is consistent with Python:NoneType
has only one valueNone
.void
constant: We reuse theNULL
literal to create a "void constant":All existing instructions that return
void
return thisNULL
value. In theory, the following snippet is valid, but stupid:Remove the
RETVOID
instruction: UseRET <@void> @VOID
instead, or simplyRET @VOID
.Remove the
SWAPSTACK
clausePASS_VOID
: UsePASS_VAL <@void> @VOID
instead. UnlikeRET
, the type parameter here is necessary: the type that the swappee expects is dynamic. It may expect a different type at a differentSWAPSTACK
site. Guessing the wrong type while swapping has undefined behaviour.Trap handlers no longer needs a PASS_VOID return case: Instead, pass a
NULL
constant.New ways to use
void
In addition to the existing three ways, i.e. empty objects, hybrid fixed part, empty return value,
void
can now be used in the following ways:RET
to return from a function ofvoid
return type.SWAPSTACK
to swap to a stack that does not expect to receive a value (it receives theNULL
value of thevoid
type).They all fit into the category that "the other end of communication" does not pass a value.
Things that should still be forbidden
void
must not be a parameter type: I don't have a very compelling reason, but it is completely useless (only increases the apparent arity of a function).void
must not be part of a struct/array/vector or the variable part of a hybrid: Not allowing this will gain us a very nice property: each field/element in any struct/array/vector/varpart has a different offset. Instruct<@i32 void void void void @x>
, sincevoid
should have size 0 and alignment 1 (in the sensevoid
can be allocated at any address a such that a % 1 == 0), void does occupy space. Then all of the void fields are at the same offset as@x
. Another reason: C does not allow void to be a struct field.Empty structs (
struct<>
) should be forbidden: For the same reason asvoid
as a field. Just usevoid
because it is so special. C forbids empty structs, too, but GCC allows it.How about LLVM?
LLVM IR has two syntax for the
ret
instruction:ret <type> <value>
for example:ret i32 100
ret void
this returns void.LLVM does not have "void constant", either, since
void
is not a "first class type".LLVM
void
is not a "first class type". Onlyvoid
and function types are not "first class type". LLVM has both "function" types and "pointer to function" types.LLVM LangRef does not say parameter types cannot be
void
, butvoid
is never used as parameter types. In C,void
is an incomplete type, and thus cannot be a parameter type.The text was updated successfully, but these errors were encountered: