feat: switch from C to LLVM IR code generation
- Replace all C code generation with LLVM IR (flat DFA model with bb_ prefix labels to avoid SSA value name collisions) - Remove c.min.js, add llvm.min.js highlight.js language definition - Update shell.nix: gcc -> clang, remove sdl3/mesa deps - Download LLVM Language Reference to docs/llvm/LangRef.html - Rename #c-code to #ir-code in HTML, JS, and CSS - Replace _generateIncludes with _generateLLVMDecls for extern function declarations using LLVM_DECL_MAP - Add string pool (CodeGen.allocString, stringGlobal, llvmStringArg) for LLVM IR global string constants with getelementptr references
This commit is contained in:
+37
-44
@@ -190,29 +190,27 @@ class WCProgram extends HTMLElement {
|
||||
return { boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs };
|
||||
}
|
||||
|
||||
_generateIncludes(proccalls, hasStrings) {
|
||||
const libNames = new Set();
|
||||
for (const p of proccalls) {
|
||||
const qname = p._selectedProc;
|
||||
if (qname) {
|
||||
const lib = qname.split("/")[0];
|
||||
if (lib) libNames.add(lib);
|
||||
_generateLLVMDecls(proccalls) {
|
||||
var seen = new Set();
|
||||
var lines = [];
|
||||
for (var pi = 0; pi < proccalls.length; pi++) {
|
||||
var qname = proccalls[pi]._selectedProc;
|
||||
if (!qname || seen.has(qname)) continue;
|
||||
seen.add(qname);
|
||||
var decl = LLVM_DECL_MAP[qname];
|
||||
if (decl) {
|
||||
lines.push(decl);
|
||||
} else {
|
||||
var fn = qname.split("/")[1] || qname;
|
||||
lines.push("declare i32 @" + fn + "(...)");
|
||||
}
|
||||
}
|
||||
let includes = Array.from(libNames).map(l => {
|
||||
const path = INCLUDE_MAP[l] || (l + ".h");
|
||||
return `#include <${path}>`;
|
||||
}).join("\n");
|
||||
if (hasStrings) {
|
||||
const hdr = "#include <stdlib.h>\n#include <string.h>";
|
||||
includes = includes ? includes + "\n" + hdr : hdr;
|
||||
}
|
||||
return includes;
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
generateCode() {
|
||||
const outputEl = $id("c-code");
|
||||
if (!outputEl) { showError("Missing #c-code output element"); return; }
|
||||
const outputEl = $id("ir-code");
|
||||
if (!outputEl) { showError("Missing #ir-code output element"); return; }
|
||||
|
||||
const { usedQuantities, usedUnits } = this._gatherUsedTypes();
|
||||
|
||||
@@ -220,51 +218,46 @@ class WCProgram extends HTMLElement {
|
||||
const unitDefs = this._generateUnitDefs(usedUnits);
|
||||
const { boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs } = this._generateVariableDeclarations();
|
||||
|
||||
const hasStrings = $id("variable-area").querySelectorAll("wc-string").length > 0;
|
||||
const stringStruct = hasStrings
|
||||
? "typedef struct { char *data; long int length; } string;\n\n"
|
||||
: "";
|
||||
CodeGen.resetStringPool();
|
||||
|
||||
const firstChild = this.firstElementChild;
|
||||
const body = firstChild && typeof CodeGen.emitFlat === "function"
|
||||
? CodeGen.emitFlat(firstChild)
|
||||
: "\n// (no flowchart body)\n";
|
||||
const proccalls = this.querySelectorAll("wc-proccall");
|
||||
const includes = this._generateIncludes(proccalls, hasStrings);
|
||||
: "; no flowchart body\n";
|
||||
|
||||
// Collect external function declarations from used libraries
|
||||
const proccalls = this.querySelectorAll("wc-proccall");
|
||||
const decls = this._generateLLVMDecls(proccalls);
|
||||
|
||||
// Collect string globals
|
||||
const strPool = CodeGen.getStringPool();
|
||||
const globals = strPool.map(function (_, i) { return CodeGen.stringGlobal(i); }).join("\n");
|
||||
|
||||
// Variable declarations -> alloca instructions in the prologue
|
||||
const dataSection = (boolDefs || scalarDefs || vectorDefs || stringDefs || arrayDefs)
|
||||
? [boolDefs, scalarDefs, vectorDefs, stringDefs, arrayDefs]
|
||||
.filter(Boolean).map(s => s + "\n").join("")
|
||||
.filter(Boolean).map(function (s) { return s + "\n"; }).join("")
|
||||
: "";
|
||||
|
||||
const hasReturnOrExit =
|
||||
body.includes("\n return ") || body.includes("\n exit(");
|
||||
const raw =
|
||||
"// --- WiseCode\u00ae ---\n" +
|
||||
(includes ? includes + "\n\n" : "") +
|
||||
"int main() {\n" +
|
||||
(typeDefs ? typeDefs + "\n\n" : "") +
|
||||
(unitDefs ? unitDefs + "\n\n" : "") +
|
||||
stringStruct + dataSection + body +
|
||||
(hasReturnOrExit ? "" : "return 0;\n") +
|
||||
"}\n// --- END ---";
|
||||
const raw = CodeGen.generateIRFile(firstChild, decls, globals, dataSection);
|
||||
outputEl.textContent = raw;
|
||||
if (typeof hljs !== "undefined") hljs.highlightElement(outputEl);
|
||||
outputEl.parentElement.dataset.language = "c";
|
||||
outputEl.parentElement.dataset.language = "llvm";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps library names to their C #include paths.
|
||||
* Libraries not listed here use the default `<{name}.h>` convention.
|
||||
* Maps library/function names to their LLVM IR `declare` signature.
|
||||
* Key is the proc qname, value is the declare line.
|
||||
* Functions not listed get a generic `declare i32 @name(...)`.
|
||||
*/
|
||||
const INCLUDE_MAP = {
|
||||
"sdl3": "SDL3/SDL.h",
|
||||
"glfw": "GLFW/glfw3.h",
|
||||
"gl": "GL/gl.h",
|
||||
const LLVM_DECL_MAP = {
|
||||
"stdio/printf": "declare i32 @printf(i8*, ...)",
|
||||
"stdlib/exit": "declare void @exit(i32)",
|
||||
};
|
||||
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
// Block registry
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user