Skip to content

Commit

Permalink
Add instructions for once-init of static variables
Browse files Browse the repository at this point in the history
  • Loading branch information
GrieferAtWork committed Mar 31, 2024
1 parent 35e0287 commit edfa4a6
Show file tree
Hide file tree
Showing 26 changed files with 1,201 additions and 241 deletions.
31 changes: 27 additions & 4 deletions include/deemon/asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1388,10 +1388,27 @@
/* ASM_ 0xf099 * -------- - ------------------ */
/* ASM_ 0xf09a * -------- - ------------------ */
/* ASM_ 0xf09b * -------- - ------------------ */
/* ASM_ 0xf09c * -------- - ------------------ */
/* ASM_ 0xf09d * -------- - ------------------ */
/* ASM_ 0xf09e * -------- - ------------------ */
/* ASM_ 0xf09f * -------- - ------------------ */
#define ASM_CMPXCH_UB_LOCK 0xf09c /* [2][-0,+1] `push cmpxch PREFIX, unbound, lock' - Atomically check if PREFIX is unbound, and replace its value with a special "lock" value.
* NOTE: Unless otherwise documented, other instructions (except ASM_CMPXCH_UB_LOCK)
* will treat "lock" values the same as "unbound", whereas ASM_CMPXCH_UB_LOCK
* will block if the current value is "lock".
* NOTE: This instruction requires "PREFIX" to be `ASM_STATIC' or `ASM16_STATIC'.
* >> again:
* >> LOCK();
* >> if (PREFIX is bound) {
* >> PUSH(false);
* >> } else {
* >> if (PREFIX === lock) {
* >> WHILE_WHILE(PREFIX === lock);
* >> goto again;
* >> }
* >> PREFIX = lock;
* >> PUSH(true);
* >> }
* >> UNLOCK(); */
#define ASM_CMPXCH_UB_POP 0xf09d /* [2][-1,+1] `push cmpxch PREFIX, unbound, pop' - Atomically change PREFIX from "unbound" to "FIRST", and push true/false indicative of a change having happened. */
#define ASM_CMPXCH_POP_UB 0xf09e /* [2][-1,+1] `push cmpxch PREFIX, pop, unbound' - Atomically change PREFIX from "SECOND" to "FIRST", and push true/false indicative of a change having happened. */
#define ASM_CMPXCH_POP_POP 0xf09f /* [2][-2,+1] `push cmpxch PREFIX, pop, pop' - Atomically change PREFIX from "FIRST" to "unbound", and push true/false indicative of a change having happened. */
/* ASM_ 0xf0a0 * -------- - ------------------ */
#define ASM16_PRINT_C 0xf0a1 /* [4][-0,+0] `print const <imm16>' - Print a constant from `<imm16>' to stdout. */
#define ASM16_PRINT_C_SP 0xf0a2 /* [4][-0,+0] `print const <imm16>, sp' - Same as `ASM_PRINT_C16', but follow up by printing a space character. */
Expand Down Expand Up @@ -1457,6 +1474,8 @@
#define ASM16_CALL_EXTERN 0xf0dd /* [7][-n,+1] `push call extern <imm16>:<imm16>, #<imm8>' - Pop #<imm8> values from the stack, pack then into a Tuple, then call an external function referenced by <imm16>:<imm16>. */
#define ASM16_CALL_GLOBAL 0xf0de /* [5][-n,+1] `push call global <imm16>, #<imm8>' - Pop #<imm8> values from the stack, pack then into a Tuple, then call a function in global slot <imm16>. */
#define ASM16_CALL_LOCAL 0xf0df /* [5][-n,+1] `push call local <imm16>, #<imm8>' - Pop #<imm8> values from the stack, pack then into a Tuple, then call a function in local slot <imm16>. */

/* Reserved. */
/* ASM_ 0xf0e0 * -------- - ------------------ */
/* ASM_ 0xf0e1 * -------- - ------------------ */
/* ASM_ 0xf0e2 * -------- - ------------------ */
Expand All @@ -1473,6 +1492,8 @@
/* ASM_ 0xf0ed * -------- - ------------------ */
/* ASM_ 0xf0ee * -------- - ------------------ */
/* ASM_ 0xf0ef * -------- - ------------------ */

/* Reserved. */
/* ASM_ 0xf0f0 * -------- - ------------------ */
/* ASM_ 0xf0f1 * -------- - ------------------ */
/* ASM_ 0xf0f2 * -------- - ------------------ */
Expand All @@ -1481,6 +1502,8 @@
/* ASM_ 0xf0f5 * -------- - ------------------ */
/* ASM_ 0xf0f6 * -------- - ------------------ */
/* ASM_ 0xf0f7 * -------- - ------------------ */

/* 16-bit prefixes. */
/* ASM_ 0xf0f8 * -------- - ------------------ */
/* ASM_ 0xf0f9 * -------- - ------------------ */
#define ASM16_STACK 0xf0fa /* `stack #<imm16>' - Use an Object located on the stack as storage class.
Expand Down
5 changes: 3 additions & 2 deletions include/deemon/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -1152,9 +1152,10 @@ struct Dee_function_object {
Dee_atomic_rwlock_t fo_reflock; /* Lock used by `ASM_STATIC', `ASM_PUSH_STATIC' and `ASM_POP_STATIC' instructions when accessing `fo_refv'. */
#endif /* !CONFIG_NO_THREADS */
COMPILER_FLEXIBLE_ARRAY(DREF DeeObject *, fo_refv); /* [if(. < fo_code->co_refc), [1..1, const]]
* [if(. >= fo_code->co_refc), [0..1, lock(fo_reflock)]]
* [if(. >= fo_code->co_refc), [0..1|ITER_DONE, lock(fo_reflock)]]
* [fo_code->co_refstaticc]
* Vector of referenced objects & static variables. */
* Vector of referenced objects & static variables
* Values may be set to ITER_DONE by `ASM_CMPXCH_UB_LOCK'. */
#else /* CONFIG_EXPERIMENTAL_STATIC_IN_FUNCTION */
COMPILER_FLEXIBLE_ARRAY(DREF DeeObject *, fo_refv); /* [1..1][const][fo_code->co_refstaticc] Vector of referenced objects. */
#endif /* !CONFIG_EXPERIMENTAL_STATIC_IN_FUNCTION */
Expand Down
8 changes: 8 additions & 0 deletions include/deemon/compiler/assembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ struct asm_invoke_operand {
#define OPERAND_CLASS_DEFAULT 0x00a1 /* `default' */
#define OPERAND_CLASS_VARARGS 0x00a2 /* `varargs' */
#define OPERAND_CLASS_VARKWDS 0x00a3 /* `varkwds' */
#define OPERAND_CLASS_UNBOUND 0x00a4 /* `unbound' */
#define OPERAND_CLASS_LOCK 0x00a5 /* `lock' */
uint16_t io_class; /* Operand class (One of `OPERAND_CLASS_*'). */
union {
uint16_t io_symid; /* Symbol id. */
Expand Down Expand Up @@ -1550,6 +1552,12 @@ INTDEF WUNUSED int DCALL asm_gunwind(void);
#define asm_gincpost() (asm_incsp(), asm_put16(ASM_INCPOST))
#define asm_gdecpost() (asm_incsp(), asm_put16(ASM_DECPOST))

/* Instructions for atomic compare-and-exchange of prefixable symbols. */
#define asm_gcmpxch_ub_lock() (asm_incsp(), asm_put16(ASM_CMPXCH_UB_LOCK))
#define asm_gcmpxch_ub_pop() (asm_dicsp(), asm_put16(ASM_CMPXCH_UB_POP))
#define asm_gcmpxch_pop_ub() (asm_dicsp(), asm_put16(ASM_CMPXCH_POP_UB))
#define asm_gcmpxch_pop_pop() (asm_ddicsp(), asm_put16(ASM_CMPXCH_POP_POP))

/* Push/pop the current top value into a location on the stack, given its absolute address.
* HINT: These functions are useful because `asm_gdup_n()' / `asm_gpop_n()' use relative addresses. */
INTDEF WUNUSED int DCALL asm_gpush_stack(uint16_t absolute_stack_addr);
Expand Down
4 changes: 2 additions & 2 deletions include/deemon/compiler/lexer.def
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ DEF_WARNING(W_UASM_EXPECTED_HASH_AFTER_STACK_PREFIX, (WG_SYNTAX), WSTATE_ERROR,
DEF_WARNING(W_UASM_HASH_FLAG_ALREADY_SET_FOR_OPERAND, (WG_SYNTAX), WSTATE_ERROR, WARNF("`#' has already been used twice by this operand"))
DEF_WARNING(W_UASM_DOLLAR_FLAG_ALREADY_SET_FOR_OPERAND, (WG_SYNTAX), WSTATE_ERROR, WARNF("`$' has already been used by this operand"))
DEF_WARNING(W_UASM_CANNOT_POP_ASSEMBLY_OUTPUT_EXPRESSION, (WG_VALUE), WSTATE_WARN, WARNF("User-assembly does not provide a value for output operand `%s'", ARG(char *)))
DEF_WARNING(W_UASM_SYMBOL_ALREADY_DEFINED, (WG_SYMBOL), WSTATE_ERROR, WARNF("Assembly Symbol `%s' has already been defined", ARG(char *)))
DEF_WARNING(W_UASM_SYMBOL_ALREADY_DEFINED, (WG_SYMBOL), WSTATE_ERROR, WARNF("Assembly symbol `%s' has already been defined", ARG(char *)))
DEF_WARNING(W_UASM_DOESNT_CLEANUP_STACK, (WG_VALUE), WSTATE_WARN, WARNF("User-assembly ends without popping %lu stack entries", ARG(unsigned long)))
DEF_WARNING(W_UASM_POPPED_UNRELATED_ITEMS, (WG_VALUE), WSTATE_ERROR, WARNF("User-assembly popped %lu unrelated stack entries", ARG(unsigned long)))
DEF_WARNING(W_UASM_CANNOT_PERFORM_OPERATION_WITH_SYMBOL, (WG_VALUE), WSTATE_ERROR, WARNF("Cannot perform operation with symbol"))
Expand All @@ -555,7 +555,7 @@ DEF_WARNING(W_UASM_STACK_VARIABLE_NOT_ALLOCATED, (WG_SYMBOL, WG_VALUE), WSTATE_E
DEF_WARNING(W_UASM_EXPECTED_16BIT_IMMEDIATE_INTEGER, (WG_VALUE), WSTATE_ERROR, WARNF("Expected a 16-bit immediate, unsigned integer value"))
DEF_WARNING(W_UASM_EXPECTED_CONSTANT_EXPRESSION_AFTER_AT_CONST, (WG_CONST, WG_VALUE), WSTATE_ERROR, WARNF("Expected a constant expression after `const @'"))
DEF_WARNING(W_UASM_EXPECTED_CONSTANT_EXPRESSION_FOR_PSEUDO_INSTRUCTION, (WG_CONST, WG_VALUE), WSTATE_ERROR, WARNF("Expected a constant expression for use by a psuedo instruction"))
DEF_WARNING(W_UASM_RELOCATION_MODEL_ALREADY_DEFINED, (WG_ASM_RELOCATION_MODEL, WG_VALUE), WSTATE_ERROR, WARNF("Relocation model had already been defined when `PC' or `SP' wasn encountered after `.' in an assembly expression"))
DEF_WARNING(W_UASM_RELOCATION_MODEL_ALREADY_DEFINED, (WG_ASM_RELOCATION_MODEL, WG_VALUE), WSTATE_ERROR, WARNF("Relocation model had already been defined when `PC' or `SP' was encountered after `.' in an assembly expression"))
DEF_WARNING(W_UASM_NEED_SYMBOL_FOR_RELOCATION_MODEL, (WG_ASM_RELOCATION_MODEL, WG_VALUE), WSTATE_ERROR, WARNF("Cannot set relocation model without a symbol expression"))
DEF_WARNING(W_UASM_CANNOT_ADD_2_SYMBOLS, (WG_VALUE), WSTATE_ERROR, WARNF("Cannot add 2 operands when both contain a symbol"))
DEF_WARNING(W_UASM_CANNOT_SUB_2_SYMBOLS, (WG_VALUE), WSTATE_ERROR, WARNF("Cannot subtract 2 operands both containing undefined, or ip-relative symbols"))
Expand Down
2 changes: 2 additions & 0 deletions include/deemon/compiler/tpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ DECL_BEGIN
#define CONFIG_LANGUAGE_NO_ASM
#endif


/* TODO: Get rid of these config options (having them on is mandatory) */
#undef CONFIG_LANGUAGE_DECLARATION_DOCUMENTATION
#define CONFIG_LANGUAGE_DECLARATION_DOCUMENTATION

Expand Down
1 change: 1 addition & 0 deletions include/deemon/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ struct Dee_module_object {
#define Dee_MODULE_HASHNX(hs, perturb) (void)((hs) = ((hs) << 2) + (hs) + (perturb) + 1, (perturb) >>= 5) /* This `5' is tunable. */
#define Dee_MODULE_HASHIT(self, i) (((DeeModuleObject *)Dee_REQUIRES_OBJECT(self))->mo_bucketv + ((i) & ((DeeModuleObject *)(self))->mo_bucketm))
DREF DeeModuleObject *const *mo_importv; /* [1..1][const_if(MODULE_FDIDLOAD)][0..rs_importc][lock(MODULE_FLOADING)][const_if(MODULE_FDIDLOAD)][owned] Vector of other modules imported by this one. */
/* XXX: Make "Module" a variable-length object and inline "mo_globalv" */
DREF DeeObject **mo_globalv; /* [0..1][lock(mo_lock)][0..mo_globalc][valid_if(MODULE_FDIDLOAD)][owned] Vector of module-private global variables. */
DREF struct Dee_code_object *mo_root; /* [0..1][lock(mo_lock)][const_if(MODULE_FDIDLOAD)] Root code object (Also used as constructor).
* HINT: Other code objects are addressed through constant/static variables.
Expand Down
1 change: 0 additions & 1 deletion include/deemon/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -3539,7 +3539,6 @@ DFUNDEF WUNUSED NONNULL((1, 2, 3)) DREF DeeObject *(DCALL DeeObject_ThisCallTupl
/* Generate and return the hash of a given object. */
DFUNDEF WUNUSED /*ATTR_PURE*/ NONNULL((1)) Dee_hash_t (DCALL DeeObject_Hash)(DeeObject *__restrict self);
DFUNDEF WUNUSED /*ATTR_PURE*/ ATTR_INS(1, 2) Dee_hash_t (DCALL DeeObject_Hashv)(DeeObject *const *__restrict object_vector, size_t object_count);
DFUNDEF WUNUSED /*ATTR_PURE*/ ATTR_INS(1, 2) Dee_hash_t (DCALL DeeObject_XHashv)(DeeObject *const *__restrict object_vector, size_t object_count);

/* GC operator invocation. */
DFUNDEF NONNULL((1, 2)) void (DCALL DeeObject_Visit)(DeeObject *__restrict self, Dee_visit_t proc, void *arg);
Expand Down
4 changes: 4 additions & 0 deletions lib/rt/bytecode.dee
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ final global ASM_REDUCE_MAX = 0xf095;
final global ASM_REDUCE_SUM = 0xf096;
final global ASM_REDUCE_ANY = 0xf097;
final global ASM_REDUCE_ALL = 0xf098;
final global ASM_CMPXCH_UB_LOCK = 0xf09c;
final global ASM_CMPXCH_UB_POP = 0xf09d;
final global ASM_CMPXCH_POP_UB = 0xf09e;
final global ASM_CMPXCH_POP_POP = 0xf09f;
final global ASM16_PRINT_C = 0xf0a1;
final global ASM16_PRINT_C_SP = 0xf0a2;
final global ASM16_PRINT_C_NL = 0xf0a3;
Expand Down
2 changes: 1 addition & 1 deletion src/deemon/compiler/asm/assembler.c
Original file line number Diff line number Diff line change
Expand Up @@ -3532,7 +3532,7 @@ code_docompile(struct ast *__restrict code_ast) {
goto err;
}

/* Merge const + static variables. */
/* Merge ref + static variables. */
if unlikely(asm_mergestatic())
goto err;

Expand Down
4 changes: 2 additions & 2 deletions src/deemon/compiler/asm/gencall.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ asm_gcall_func(struct ast *__restrict func,
return -1;
}

PRIVATE WUNUSED NONNULL((2)) int DCALL
asm_gargv(size_t argc, struct ast **__restrict argv) {
PRIVATE WUNUSED ATTR_INS(2, 1) int DCALL
asm_gargv(size_t argc, struct ast *const *argv) {
size_t i;
for (i = 0; i < argc; ++i) {
if (ast_genasm_one(argv[i], ASM_G_FPUSHRES))
Expand Down
18 changes: 17 additions & 1 deletion src/deemon/compiler/asm/genstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,18 @@ INTERN WUNUSED NONNULL((1, 2, 3)) int
case SYMBOL_TYPE_STATIC:
if (!(dst_sym->s_flag & SYMBOL_FALLOC)) {
#ifdef CONFIG_EXPERIMENTAL_STATIC_IN_FUNCTION
if (dst->a_scope != dst_sym->s_scope) {
/* TODO: Warn about initial store to static variable
* happening in different score than declaration. */
} else if (dst->a_ddi.l_file && dst_sym->s_decl.l_file &&
(dst->a_ddi.l_file != dst_sym->s_decl.l_file ||
dst->a_ddi.l_line != dst_sym->s_decl.l_line ||
dst->a_ddi.l_col != dst_sym->s_decl.l_col)) {
/* TODO: Warn that only an assignment to the initial
* declaration is portable for the purpose of
* having the initializer only run once. */
}

/* TODO: In the new static variable model, the first assignment should
* still only be executed *once*, however this definitely needs
* a special instruction that store a value in a static *only* if
Expand All @@ -1573,11 +1585,15 @@ INTERN WUNUSED NONNULL((1, 2, 3)) int
* >> push const @42 # Value to store
* >> push cmpxch static @x, unbound, pop # Pushes true/false indicative of cmpxch success
* >> pop # Get rid of the true/false
* XXX: Why not have the caller assign the initial static value?
* >> push const @42
* >> push function const 1, #1 // Code has 0 refs, but allow caller to pre-assign statics
*
* In order to execute initializers with side-effects:
* >> static local x = foo();
*
* ASM:
* >> push startinit static @x # Pushes "true" if initialization started, "false" otherwise
* >> push cmpxch static @x, unbound, initializing # Pushes "true" if initialization started, "false" otherwise
* >> jf pop, 1f
* >> .Linit_except_start:
* >> call @foo, #1
Expand Down
8 changes: 8 additions & 0 deletions src/deemon/compiler/asm/parseasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1735,6 +1735,14 @@ do_parse_operand(struct asm_invoke_operand *__restrict result,
result->io_class = OPERAND_CLASS_VARKWDS;
goto done_yield_1;
}
if (IS_KWD_NOCASE("unbound")) {
result->io_class = OPERAND_CLASS_UNBOUND;
goto done_yield_1;
}
if (IS_KWD_NOCASE("lock")) {
result->io_class = OPERAND_CLASS_LOCK;
goto done_yield_1;
}
}
/* Fallback: Parse an address expression. */
if unlikely(uasm_parse_intexpr(&result->io_intexpr,
Expand Down
8 changes: 8 additions & 0 deletions src/deemon/compiler/asm/userasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ asm_invoke_operand_print(struct asm_invoke_operand *__restrict self,

case OPERAND_CLASS_VARKWDS:
raw_operand_string = "varkwds";
goto do_raw_string;

case OPERAND_CLASS_UNBOUND:
raw_operand_string = "unbound";
goto do_raw_string;

case OPERAND_CLASS_LOCK:
raw_operand_string = "lock";
do_raw_string:
temp = ascii_printer_print(printer,
raw_operand_string,
Expand Down
19 changes: 19 additions & 0 deletions src/deemon/compiler/asm/userdb.def
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ for (local x: names) {
#define DEFAULT OPERAND_CLASS_DEFAULT
#define VARARGS OPERAND_CLASS_VARARGS
#define VARKWDS OPERAND_CLASS_VARKWDS
#define UNBOUND OPERAND_CLASS_UNBOUND
#define LOCK OPERAND_CLASS_LOCK
#define POP_DOTS OPERAND_CLASS_POP_DOTS
#define SPPOP OPERAND_CLASS_SPPOP
#define SPADDIMM_EQ_N2 OPERAND_CLASS_SPADDIMM_EQ_N2
Expand Down Expand Up @@ -1183,6 +1185,21 @@ INSTR("mov", (
O2(ASM_POP_LOCAL, FF0, (LOCAL)(PREFIX)) /* `mov local <imm8/16>, PREFIX' */
))

/* CONSTRAINTS: `cmpxch <p>, unbound, lock' (only when "<p>" is a static variable) */
/* CONSTRAINTS: `cmpxch <p>, unbound, <s>' */
/* CONSTRAINTS: `cmpxch <p>, <s>', unbound */
/* CONSTRAINTS: `cmpxch <p>, <s>', <s> */
INSTR("cmpxch", (
O2(ASM_CMPXCH_UB_LOCK, FPREFIX | FPUSH, (UNBOUND)(LOCK)) /* `PREFIX: push cmpxch unbound, lock' */
O3(ASM_CMPXCH_UB_LOCK, FPUSH, (PREFIX)(UNBOUND)(LOCK)) /* `push cmpxch PREFIX, unbound, lock' */
O2(ASM_CMPXCH_UB_POP, FPREFIX | FPUSH, (UNBOUND)(POP)) /* `PREFIX: push cmpxch unbound, pop' */
O3(ASM_CMPXCH_UB_POP, FPUSH, (PREFIX)(UNBOUND)(POP)) /* `push cmpxch PREFIX, unbound, pop' */
O2(ASM_CMPXCH_POP_UB, FPREFIX | FPUSH, (POP)(UNBOUND)) /* `PREFIX: push cmpxch pop, unbound' */
O3(ASM_CMPXCH_POP_UB, FPUSH, (PREFIX)(POP)(UNBOUND)) /* `push cmpxch PREFIX, pop, unbound' */
O2(ASM_CMPXCH_POP_POP, FPREFIX | FPUSH, (POP)(POP)) /* `PREFIX: push cmpxch pop, pop' */
O3(ASM_CMPXCH_POP_POP, FPUSH, (PREFIX)(POP)(POP)) /* `push cmpxch PREFIX, pop, pop' */
))

/* clang-format on */

/*[[[deemon
Expand Down Expand Up @@ -1249,6 +1266,8 @@ for (local x: names) {
#undef SPADDIMM_EQ_N2
#undef SPPOP
#undef POP_DOTS
#undef LOCK
#undef UNBOUND
#undef VARKWDS
#undef VARARGS
#undef DEFAULT
Expand Down
Loading

0 comments on commit edfa4a6

Please sign in to comment.