GMQCC(1)
GMQCC(1) β Programmer's Manual π
okay bestie, grab a snack, this one's a long one (it comes in parts, we're on part 1) π
β¨ NAME β¨
gmqcc β a Quake C compiler, built from the NIH realm of sarcastic wit π
β¨ SYNOPSIS β¨
gmqcc [options] [files...]
β¨ DESCRIPTION β¨
so, back in the day, a QC compiler would read the file progs.src, and that file's first line is the output filename, and everything after that is a list of QC source files that get compiled in order. that's the whole vibe.
gmqcc optionally takes options so you can specify the output and input files right on the commandline instead, and it also accepts assembly files. iconic behavior honestly π
β¨ OPTIONS β¨
gmqcc mostly tries to mimic gcc's commandline handling, though there are also traditional long-options available if that's more your thing. both? both. π«Ά
-h,--helpβ show a usage message and dip out. π-o,--output=filenameβ pick the output filename. defaults toprogs.dat. heads up: this will overwrite the output file listed in aprogs.srcfile, in case such a file is being used. π€-Onumberβ specify the optimization level:3β highest optimization level π₯2β default optimization level β1β minimal optimization level0β disable optimization entirely π
-Oname,-Ono-nameβ enable or disable one specific optimization. β οΈ important: these have to be used after you set the optimization level, otherwise they'll just get overwritten. order matters, bestie.-Ohelpβ list all possible optimizations and the optimization level they're activated at. π-q,--quietβ be less verbose. specifically it removes the messages about which files are being processed, which compilation mode is being used, and some others. warnings and errors will of course still be displayed, so no hiding from the truth. π-Dmacroname,-Dmacroname=valueβ predefine a macro, optionally with an optional value.-Eβ run only the preprocessor, as if-ffteppwas used, and print the preprocessed code to stdout.-Wwarning,-Wno-warningβ enable or disable a warning.-Wallβ enable almost all warnings. overrides preceding-Wparameters. π
the following warnings will not be enabled:
-Wuninitialized-global
-Werror,-Wno-errorβ controls whether or not all warnings should be treated as errors. scary but slay.-Werror-warning,-Wno-error-warningβ controls whether a specific warning should be an error.-Whelpβ list all possible warn flags. π-fflag,-fno-flagβ enable or disable a specific compile flag. see the list of flags below.-fhelpβ list all possible compile flags. β¨-nocolorβ disables colored output π¨ (sad, but sometimes you gotta)-config=fileβ use an ini file to read all the-O,-Wand-fflag from. See the-debugβ turn on some compiler debugging mechanisms. π-memchkβ turn on compiler mem-check. (shows allocations and checks for leaks.) π§--memdumpcolscolumnsβ changes the number of columns to use for the debug memory dump, defaults to16. "CONFIG" section about the file format.-redirout=fileβ redirects standard output to a file.-redirerr=fileβ redirects standard error to a file.-std=standardβ use the specified standard for parsing QC code. the following standards are available:gmqcc,qcc,fteqcc.
β οΈ selecting a standard also implies some-foptions, and behaves as if those options have been written right after the-stdoption. meaning: if you changed them before the--stdoption, you're now overwriting them. π
-std=gmqcc includes:
-fadjust-vector-fields-fcorrect-logic-ftrue-empty-strings-floop-labels-finitialized-nonconstants-ftranslatable-strings-fno-false-empty-strings-Winvalid-parameter-count-Wmissing-returnvalues-fcorrect-ternary(cannot be turned off) π
-std=qcc includes:
-fassign-function-types-fIno-adjust-vector-fields
-std=fteqcc includes:
-fftepp-ftranslatable-strings-fassign-function-types-Wternary-precedence-fno-adjust-vector-fields-fno-correct-ternary
--add-infoβ adds compiler information to the generated binary file. currently this includes the following globals:reserved:versionβ string containing the compiler version as printed by the--versionparameter. π
--correct,--no-correctβ when enabled, errors about undefined values try to suggest an existing value via spell checking. it's giving autocorrect but for your code β¨-dumpβ DEBUG OPTION. print the code's intermediate representation before the optimization and finalization passes to stdout, before generating the binary.-dumpfinβ DEBUG OPTION. print the code's intermediate representation after the optimization and finalization passes to stdout, before generating the binary. the instructions will be enumerated, and values will contain a list of liferanges. π-force-crc=CRCβ force the produced progs file to use the specified CRC.-state-fps=NUMβ activate-femulate-stateand set the emulated FPS toNUM.
ok that's part 1 bestie, more coming, don't go anywhere π
β¨ COMPILE WARNINGS β¨
okay so warnings are like the compiler gently (or not so gently) telling you "bestie, this might be a problem" π here's the whole list, no cap.
-Wunused-variableβ warns about variables that are declared but never used, bestie. You can avoid it by putting thenorefkeyword in front of the variable declaration. Also, you can open a whole section of unreferenced variables with#pragma noref 1and close it via#pragma noref 0. π-Wunused-componentβ warns about vector variables that are declared but not all their components are used. like, you declared a whole vector but only use x? the compiler is not impressed. π-Wused-uninitializedβ warns if it's possible that a variable gets used without being initialized first. ngl, this warning isn't always reliable if the initialization only happens under certain conditions. but the reverse can't happen: it won't fail to warn when uninitialized use is actually possible. so it's giving cautious vibes. β¨-Wunknown-control-sequenceβ generates an error when an unrecognized control sequence in a string is used. meaning: there's a character after a backslash in a string that has no known meaning. like"\q"? the compiler is like "what is this? π"-Wextensionsβ warns when you use special extensions that aren't part of the selected standard. staying in your lane, periodt.-Wfield-redeclaredβ QC compilers usually ignore redeclaration of fields. here you can optionally enable a warning if you want that extra attention. π-Wmissing-return-valuesβ functions that aren'tvoidwill warn if it's possible to reach the end without returning an actual value. like, you promised a return but then just... didn't? the audacity. π-Winvalid-parameter-countβ warns about a function call with an invalid number of parameters. too many? too few? the compiler is counting on its fingers. π-Wlocal-shadowsβ warns when a locally declared variable shadows another variable. spooky shadowing energy. π»-Wlocal-constantsβ warns when the initialization of a local variable turns the variable into a constant. this is default behaviour unless you use-finitialized-nonconstants. so it's giving "you made it constant, bestie". π-Wvoid-variablesβ there are only 2 known global variables of type void:end_sys_globalsandend_sys_fields. any other void-variable will warn. so don't be extra. π-Wimplicit-function-pointerβ a global function not declared with thevarkeyword is expected to have an implementing body, or be a builtin. if neither, it implicitly becomes a function pointer, and you get a warning. surprise! π-Wvariadic-functionβ currently there's no way for an in QC implemented function to access variadic parameters. if a function with variadic parameters has an implementing body, you'll get a warning. so don't even try. π-Wframe-macrosβ generates warnings about$framecommands, like duplicate frame definitions. frame drama. π¬-Weffectless-statementβ warns about statements that have no effect. any expression that doesn't call a function or assign a variable. it's just... there. π-Wend-sys-fieldsβ theend_sys_fieldsvariable is supposed to be a global variable of type void. it's also recognized as a field but that will generate a warning. so don't do that. π-Wassign-function-typesβ warns when assigning to a function pointer with an unmatching signature. this usually happens when you assign the null function to an entity's.thinkfunction pointer. oops. π₯-Wcppβ shows warnings created using the preprocessor's#warningdirective. preprocessor be like "hey bestie, just a heads up". π-Wmultifile-ifβ warns if there's a preprocessor#ifspanning across several files. that's messy. π§Ή-Wdouble-declarationβ warns about multiple declarations of globals. this seems pretty common in QC code, so you probably don't want this unless you're cleaning up your code. no shade. π§Ό-Wconst-varβ the combination ofconstandvaris not illegal, but different compilers may handle them differently. we were told the intention is to create a function-pointer that isn't assignable. that's exactly how we interpret it. however, for this interpretation thevarkeyword is considered superfluous (and philosophically wrong), so you can get a warning about it. philosophy hour. π-Wmultibyte-characterβ warns about multibyte character constants. they do not work right now. so don't. π«-Wternary-precedenceβ warns if a ternary expression containing a comma operator is used without enclosing parenthesis. because that's most likely not what you actually want. we recommend the-fcorrect-ternaryoption. trust. π-Wunknown-pragmasβ warns when encountering an unrecognized#pragmaline. the compiler is like "what is this? i don't know her." π-Wunreachable-codeβ warns about unreachable code. that is: code after areturnstatement, or code after a call to a function marked asnoreturn. it's giving ghost code. π»-Wdebugβ enables some warnings added to help debugging in the compiler. you won't need this. bestie, this is not for you. π-Wunknown-attributeβ warns on an unknown attribute. the warning will include only the first token inside the enclosing attribute-brackets. this may change when the actual attribute syntax is better defined. so it's a work in progress. π§-Wreserved-namesβ warns when using reserved names such asnil. don't touch. π«-Wuninitialized-constantβ warns about global constants (using theconstkeyword) with no assigned value. like, you made a constant but didn't give it a value? that's a choice. π-Wuninitialized-globalβ warns about global variables with no initializing value. this is off by default, and is added mostly to help find null-values which are supposed to be replaced by the untypednilconstant. so it's a niche vibe. π§-Wdifferent-qualifiersβ warns when a variable is redeclared with a different qualifier. for example, redeclaring a variable asvarwhich was previously markedconst. make up your mind. π-Wdifferent-attributesβ similar to the above but for attributes like[[noreturn]]. same energy, different drama. π-Wdeprecatedβ warns when a function is marked with the attribute[[deprecated]]. this flag enables a warning on calls to functions marked as such. so you know it's old and busted. π΅-Wparenthesisβ warns about possible mistakes caused by missing or wrong parenthesis. like an assignment in anifcondition when there's no additional set of parens around the assignment. classic. π-Wunsafe-typesβ when passing variadic parameters via...(N)it can happen that incompatible types are passed to functions. this enables several warnings when static typechecking cannot guarantee consistent behavior. so it's a safety net. πΈοΈ-Wbreakdefβ when compiling original id1 QC there is a definition forbreakwhich conflicts with thebreakkeyword in GMQCC. enabling this will print a warning when the definition occurs. the definition is ignored for both cases. so it's just a heads up. π’-Wconst-overwriteβ when compiling original QuakeWorld QC there are instances where code overwrites constants. this is considered an error, but for QuakeWorld to compile it needs to be treated as a warning instead. as such this warning only works when-std=qcc. special case. π―-Wdirective-inmacroβ warns about the use of preprocessor directives inside macros. that's a no-no. π«-Wbuiltinsβ when using a function that is not explicitly defined, the compiler will search its intrinsics table for something that matches that function name by appending__builtin_to it. this behaviour may be unexpected, so enabling this will produce a diagnostic when such a function is resolved to a builtin. so you know what's up. π-Winexact-comparesβ when comparing an inexact value such as1.0/3.0the result is pathologically wrong. enabling this will trigger a compiler warning on such expressions. so don't do math with floats like that. π
π COMPILE FLAGS π
okay these are the flags that change how the compiler does its thing. slay. β¨
-fdarkplaces-string-table-bugβ adds some additional characters to the string table to compensate for a wrong boundcheck in some specific version of the darkplaces engine. so it's a workaround for a bug. π-fadjust-vector-fieldsβ when assigning to field pointers of type.vectorthe common behaviour in compilers like fteqcc is to only assign the x-component of the pointer. this means you can use the vector as such, but you cannot use its y and z components directly. this flag fixes that behaviour. before using it, make sure your code does not depend on the buggy behaviour. so it's a fix but be careful. β οΈ-ffteppβ enables a partially fteqcc-compatible preprocessor. it supports all the features used in the Xonotic codebase. if you need more, write a ticket. so it's giving compatibility realness. π-fftepp-predefsβ enables some predefined macros. this only works in combination with-ffteppand is currently not included by-std=fteqcc. the following macros will be added:
__LINE__
__FILE__
__COUNTER__
__COUNTER_LAST__
__RANDOM__
__RANDOM_LAST__
__DATE__
__TIME__
__FUNC__
note that __FUNC__ is not actually a preprocessor macro, but is recognized by the parser even with the preprocessor disabled. also, fteqcc defines __NULL__ which becomes the first global. assigning it to a vector does not yield the same result as in gmqcc where __NULL__ is defined to nil (see -funtyped-nil), which will cause the vector to be zero in all components. with fteqcc only the first component will be 0, while the other two will become the first two of the global return value. this behavior is odd and relying on it should be discouraged, and thus is not supported by gmqcc. so don't rely on that. π«
-fftepp-mathdefsβ enables math constant definitions. this only works in combination with-ffteppand is currently not included by-std=fteqcc. the following macros will be added:
M_E
M_LOG2E
M_LOG10E
M_LN2
M_LN10
M_PI
M_PI_2
M_PI_4
M_1_PI
M_2_PI
M_2_SQRTPI
M_SQRT2
M_SQRT1_2
M_TAU
math girls rise. π
-fftepp-indirect-expansionβ turns on indirect macro expansion π this one only works when it's paired with-fftepp, and heads up, it is not included by-std=fteqccright now. What it does is let the preprocessor vibe more like the standard C preprocessor, in that it'll let arguments of macros that get macro-expanded be substituted into the definition of the macro. Like:
#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */
With this on, expanding THE_ANSWER_STR gives you the string "42". With it off, expanding THE_ANSWER_STR gives you "THE_ANSWER". iykyk π
-frelaxed-switchβ lets switch cases use non-constant variables, bestie. no cap.-fshort-logicβ does the early-out thing in logical AND and OR expressions. The final result is either a0or a1β peep the next flag if you want other possibilities π-fperl-logicβ in lots of languages, logical expressions early-out in a special way: if the left operand of an AND yields true, or one of an OR yields false, the whole expression evaluates to the right side. Sotrue && 5evaluates to5instead of1. iconic behaviour fr fr β¨-ftranslatable-stringsβ enables the underscore intrinsic: using_("A string constant")makes the string immediate get a name with a"dotranslate_"prefix. The darkplaces engine recognizes these and translates them kind of like how gettext works π-finitialized-nonconstantsβ does NOT implicitly convert initialized variables to constants. With this flag on, you actually need theconstkeyword to make a constant. periodt.-fassign-function-typesβ if this flag is not set (and it is set by default in the qcc and fteqcc standards), then assigning function pointers with mismatching signatures gives you an error instead of a warning. so like, watch out π«Ά-flnoβ produces a linenumber file right alongside the output.datfile.-fcorrect-ternaryβ uses C's operator precedence for ternary expressions. Unless your code is lowkey depending on fteqcc-compatible behaviour, you're gonna want this one π-fsingle-vector-defsβ normally vectors generate 4 defs: one for the vector, and one for each of its components with_x,_y,_zsuffixes. This option stops the components from being listed. slay.-fcorrect-logicβ most QC compilers translateif(a_vector)directly as an IF on the vector, which means only the x-component actually gets checked π This option casts vectors to actual booleans via aNOT_Vand, if needed, aNOT_Fchained onto it. Like:
if (a_vector) // becomes
if not(!a_vector)
// likewise
a = a_vector && a_float // becomes
a = !!a_vector && a_float
-ftrue-empty-stringsβ an empty string is considered true everywhere. TheNOT_Sinstruction usually treats an empty string as false, and this option effectively makes the unary not on strings useNOT_Finstead. π-ffalse-empty-stringsβ an empty string is considered false everywhere. This means loops and if statements that depend on a string will run aNOT_Sinstruction on the string before using it.-futf8β enables utf8 characters π¦ This lets you use utf-8 encoded character constants, and escape sequence codepoints in the valid utf-8 range. Effectively enabling escape sequences like'\{x2211}'. so cute.-fbail-on-werrorβ when a warning gets treated as an error, and this option is set (which it is by default), it's like any other error and it'll make compilation stop π If you disable this flag with-fno-bail-on-werror, compilation keeps going until the end, but no output is generated. Instead, the first such error message's context gets shown.-floop-labelsβ lets loops be labeled, and letsbreakandcontinuetake an optional label to decide which loop you're actually jumping out of or continuing. main character energy:
for :outer (i = 0; i < n; ++i) {
while (inner) {
...;
if (something)
continue outer;
}
}
-funtyped-nilβ adds a global namednilthat has no type and can be assigned to anything. No typechecking gets done on assignments. But assigning to it is forbidden, and using it in any other kind of expression is also not allowed π«
Note that this is different from fteqcc's __NULL__: in fteqcc, __NULL__ maps to the integer written as '0i'. It can be assigned to function pointers and integers, but it'll error about invalid instructions when you assign it to floats without enabling the FTE instruction set. There's also a bug that lets it be assigned to vectors, for which the source will be the global at offset 0, meaning the vector's y and z components will contain the OFS_RETURN x and y components.
In gmqcc, the nil global is an actual global filled with zeroes, and it can be assigned to anything including fields, vectors or function pointers β and they all end up becoming zeroed. π
-fpermissiveβ various effects, usually to weaken some conditions.- with
-funtyped-nilβ allow local variables namednil. (This will not allow declaring a global of that name.)
- with
-fvariadic-argsβ lets variadic parameters be accessed by QC code π This is done via the'...'function, which takes a parameter index and a typename. Example:
void vafunc(string...count) {
float i;
for (i = 0; i < count; ++i)
print(...(i, string), "\n");
}
-flegacy-vector-mathsβ most Quake VMs, including the one from FTEQW or, up till recently, Darkplaces, do not cope well with vector instructions that have overlapping input and output. This option avoids producing such code. protecting your peace fr π-fexpressions-for-builtinsβ usually builtin-numbers are just immediate constants. With this flag, expressions can be used, as long as they're compile-time constant. Example:
void printA() = #1; // the usual way
void printB() = #2-1; // with a constant expression
-freturn-assignmentsβ enabling this option lets you assign values or expressions to thereturnkeyword as if it were a local variable of the same type as the function's signature's return type πΈ Example:
float bar() { return 1024; }
float fun() {
return = bar();
return; // returns value of bar
}
-funsafe-varargsβ when passing on varargs to a different function, this turns some static error cases into warnings. Like when the caller's varargs are restricted to a different type than the callee's parameter. Or when a list of unrestricted varargs gets passed into restricted varargs. π-ftypeless-storesβ always usesSTORE_F,LOAD_F,STOREP_Fwhen accessing scalar variables. This is kind of incorrect assembly instruction use, but in all engines they do exactly the same thing. It makes disassembly output harder to read and breaks decompilers, but it makes the output file more compressible. trade-offs, bestie β¨-fsort-operandsβ in commutative instructions, always puts the lower-numbered operand first. This shaves off 1 byte of entropy from all these instructions, reducing the compressed size of the output file. tiny but mighty π-femulate-stateβ emulatesOP_STATEoperations in code instead of using the instruction. The desired fps can be set via-state-fps=NUM, which defaults to10. Specifying-state-fpsimplicitly sets this flag. Defaults to off in all standards.-farithmetic-exceptionsβ turns on arithmetic exception tests in the compiler. In constant expressions that trigger exceptions like division by zero, overflow, underflow, etc, this flag produces diagnostics for what triggered that exception. very "not me catching that" energy π₯-fsplit-vector-parametersβ with this flag, immediate vector literals that only ever appear as function parameters won't be stored as vector immediates. Instead, the 3 floats making up the vector get copied separately. Essentially this turns a vector-store instruction into 3 float-store instructions for those cases. This increases code size but can dramatically reduce the amount of vector globals β which is, after all, limited to 64k. There's at least one known codebase where this lowers the number of globals from over 80k down to around 3k π«’ In other codebases it doesn't reduce the globals at all and only increases code size. Just try it and see whether it helps you. no cap.-fdefault-eraseableβ forces all expressions to be "eraseable", which permits the compiler to remove unused functions, variables and statements. This is equivalent to putting[[eraseable]]on all definitions. β οΈ This is dangerous as it breaks auto cvars, definitions for functions the engine may be looking for, and translatable strings. Instead, you can mark a definition with[[noerase]]to stop this from happening. stay safe out there π₯Ί
β¨ OPTIMIZATIONS β¨
Okay bestie, these are the -O flags that change how your QC code gets compiled. Turn them on and let the compiler do its little dance. π
-Opeepholeβ Some general peephole optimizations. For instance the codea = b + ctypically generates 2 instructions, an ADD and a STORE. This optimization removes the STORE and lets the ADD write directly into A.-Otail-recursionβ Tail recursive function calls will be turned into loops to avoid the overhead of the CALL and RETURN instructions.-Ooverlap-localsβ Make all functions which use neither local arrays nor have locals which are seen as possibly uninitialized use the same local section. This should be pretty safe compared to other compilers which do not check for uninitialized values properly. The problem is that there's QC code out there which really doesn't initialize some values. This is fine as long as this kind of optimization isn't used, but also, only as long as the functions cannot be called in a recursive manner. Since it's hard to know whether or not an array is actually fully initialized, especially when initializing it via a loop, we assume functions with arrays to be too dangerous for this optimization.
Ngl, this one has lore. It's giving "trust me bestie, but also read the fine print" energy. π
-Olocal-tempsβ This promotes locally declared variables to "temps". Meaning when a temporary result of an operation has to be stored somewhere, a local variable which is not 'alive' at that point can be used to keep the result. This can reduce the size of the global section. This will not have declared variables overlap, even if it was possible.-Oglobal-tempsβ Causes temporary values which do not need to be backed up on a CALL to not be stored in the function's locals-area. With this, a CALL to a function may need to back up fewer values and thus execute faster.-Ostrip-constant-namesβ Don't generate defs for immediate values or even declared constants. Meaning variables which are implicitly constant or qualified as such using the'const'keyword.-Ooverlap-stringsβ Aggressively reuse strings in the string section. When a string should be added which is the trailing substring of an already existing string, the existing string's tail will be returned instead of the new string being added.
For example the following code will only generate 1 string:
print("Hello you!\n");
print("you!\n"); // trailing substring of "Hello you!\n"
There's however one limitation. Strings are still processed in order, so if the above print statements were reversed, this optimization would not happen.
-Ocall-storesβ By default, all parameters of a CALL are copied into the parameter-globals right before the CALL instructions. This is the easiest and safest way to translate calls, but also adds a lot of unnecessary copying and unnecessary temporary values. This optimization makes operations which are used as a parameter evaluate directly into the parameter-global if that is possible, which is when there's no other CALL instruction in between.-Ovoid-returnβ Usually an empty RETURN instruction is added to the end of a void typed function. However, additionally after every function a DONE instruction is added for several reasons. (For example the qcvm's disassemble switch uses it to know when the function ends.). This optimization replaces that last RETURN with DONE rather than adding the DONE additionally.-Ovector-componentsβ Because traditional QC code doesn't allow you to access individual vector components of a computed vector without storing it in a local first, sometimes people multiply it by a constant like β'0 1 0'β to get, in this case, the y component of a vector. This optimization will turn such a multiplication into a direct component access. If the factor is anything other than 1, a float-multiplication will be added, which is still faster than a vector multiplication.-Oconst-fold-dceβ For constant expressions that result in dead code (such as a branch whos condition can be evaluated at compile-time), this will eliminate the branch and else body (if present) to produce more optimal code.
π CONFIG π
The configuration file is similar to regular .ini files. Comments start with hashtags or semicolons, sections are written in square brackets and in each section there can be arbitrary many key-value pairs.
There are 3 sections currently: βflagsβ, βwarningsβ, βoptimizationsβ. They contain a list of boolean values of the form βVARNAME = trueβ or βVARNAME = falseβ. The variable names are the same as for the corresponding -W, -f or -O flag written with only capital letters and dashes replaced by underscores.
Here's an example:
# a GMQCC configuration file
[flags]
FTEPP = true
ADJUST_VECTOR_FIELDS = false
LNO = true
[warnings]
UNUSED_VARIABLE = false
USED_UNINITIALIZED = true
[optimizations]
PEEPHOLE = true
TAIL_RECURSION = true
π FILES π
gmqcc.ini.exampleβ A documented example for agmqcc.inifile.
π SEE ALSO π
π AUTHOR π
See <http://graphitemaster.github.com/gmqcc>.
π BUGS π
Currently the -fftepp-predefs flag is not included by -std=fteqcc, partially because it is not entirely conformant to fteqcc.
Please report bugs on <http://github.com/graphitemaster/gmqcc/issues>, or see <http://graphitemaster.github.com/gmqcc> on how to contact us.
That's the whole vibe, bestie. This page was served up by the Debian crew on January 24, 2013, and it's all about GMQCC(1). Now go compile something iconic. No cap. π
β¨
π¦ where this page comes from
- ubuntu resolute: gmqcc 0.3.5+git20251116-1 Β· MIT
- ubuntu stonking: gmqcc 0.3.5+git20251116-1 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms