summaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
Diffstat (limited to 'extras')
-rwxr-xr-xextras/check-ir-stable-names-gh-actions.sh29
-rw-r--r--extras/check-ir-stable-names.lua280
2 files changed, 309 insertions, 0 deletions
diff --git a/extras/check-ir-stable-names-gh-actions.sh b/extras/check-ir-stable-names-gh-actions.sh
new file mode 100755
index 000000000..78c9945a6
--- /dev/null
+++ b/extras/check-ir-stable-names-gh-actions.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+set -e
+
+# The github action runners don't have libreadline and we don't need it
+make -C external/lua MYCFLAGS="-DLUA_USE_POSIX" MYLIBS=""
+external/lua/lua -v
+
+# Run the check
+if ! ./external/lua/lua extras/check-ir-stable-names.lua check; then
+ echo "Check failed. Running update..."
+ ./external/lua/lua extras/check-ir-stable-names.lua update
+
+ echo -e "\n=== Diff of changes made ==="
+ git diff --no-index --color=always source/slang/slang-ir-insts-stable-names.lua || true
+
+ # Also create a summary for GitHub Actions
+ if [ -n "$GITHUB_STEP_SUMMARY" ]; then
+ {
+ echo "## IR Stable Names Table Update Required"
+ echo "The following changes need to be made to \`source/slang/slang-ir-insts-stable-names.lua\`:"
+ echo '```diff'
+ git diff --no-index source/slang/slang-ir-insts-stable-names.lua
+ echo '```'
+ } >>"$GITHUB_STEP_SUMMARY"
+ fi
+
+ # Fail the job since the check failed
+ exit 1
+fi
diff --git a/extras/check-ir-stable-names.lua b/extras/check-ir-stable-names.lua
new file mode 100644
index 000000000..90cff4683
--- /dev/null
+++ b/extras/check-ir-stable-names.lua
@@ -0,0 +1,280 @@
+-- Helper function to flatten the instruction hierarchy
+local function flatten_instructions(insts, prefix, result)
+ prefix = prefix or ""
+ result = result or {}
+
+ for _, entry in ipairs(insts) do
+ for name, data in pairs(entry) do
+ local full_name = prefix == "" and name or (prefix .. "." .. name)
+
+ -- If it's a table with numeric indices, it has children
+ if type(data) == "table" and #data > 0 then
+ flatten_instructions(data, full_name, result)
+ else
+ -- Add the current instruction
+ table.insert(result, full_name)
+ end
+ end
+ end
+
+ return result
+end
+
+-- Load instruction definitions
+local function load_instructions(filename)
+ local chunk, err = loadfile(filename)
+ if not chunk then
+ error("Failed to load instruction file: " .. filename .. " - " .. (err or "unknown error"))
+ end
+
+ -- Just execute it normally
+ local result = chunk()
+
+ -- If the file sets a global 'insts', use that
+ if result.insts then
+ return result.insts
+ end
+
+ error("Instruction file must return a table with 'insts' entry")
+end
+
+-- Load stable names table
+local function load_stable_names(filename)
+ local file = io.open(filename, "r")
+ if not file then
+ -- File doesn't exist, return empty table
+ return {}
+ end
+ file:close()
+
+ local chunk, err = loadfile(filename)
+ if not chunk then
+ error("Failed to load stable names file: " .. filename .. " - " .. (err or "unknown error"))
+ end
+
+ local result = chunk()
+
+ -- Validate structure
+ if type(result) ~= "table" then
+ error("Stable names file must return a table")
+ end
+
+ for name, id in pairs(result) do
+ if type(name) ~= "string" then
+ error(string.format("Invalid key: expected string, got %s", type(name)))
+ end
+ if type(id) ~= "number" then
+ error(string.format("Invalid value for '%s': expected number, got %s", name, type(id)))
+ end
+ end
+
+ return result
+end
+
+-- Save stable names table
+local function save_stable_names(filename, stable_names)
+ local file, err = io.open(filename, "w")
+ if not file then
+ error("Failed to open file for writing: " .. filename .. " - " .. (err or "unknown error"))
+ end
+
+ file:write("-- This file is machine generated! any entries written below will be preserved,\n")
+ file:write("-- but things like comments or anything outside the schema won't be preserved\n")
+ file:write("return {\n")
+
+ -- Sort by ID for consistent output
+ local sorted_entries = {}
+ for name, id in pairs(stable_names) do
+ table.insert(sorted_entries, { name = name, id = id })
+ end
+ table.sort(sorted_entries, function(a, b)
+ return a.id < b.id
+ end)
+
+ for _, entry in ipairs(sorted_entries) do
+ -- Escape quotes in name
+ local escaped_name = entry.name:gsub('"', '\\"')
+ file:write(string.format('\t["%s"] = %d,\n', escaped_name, entry.id))
+ end
+ file:write("}\n")
+ file:close()
+end
+
+-- Check for unique IDs
+local function check_unique_ids(stable_names)
+ local seen_ids = {}
+ local duplicates = {}
+
+ for name, id in pairs(stable_names) do
+ if seen_ids[id] then
+ if not duplicates[id] then
+ duplicates[id] = { seen_ids[id] }
+ end
+ table.insert(duplicates[id], name)
+ else
+ seen_ids[id] = name
+ end
+ end
+
+ return duplicates
+end
+
+-- Check bijection
+local function check_bijection(inst_names, stable_names)
+ local missing_from_stable = {}
+ local extra_in_stable = {}
+
+ -- Check for instructions missing from stable names
+ for _, name in ipairs(inst_names) do
+ if stable_names[name] == nil then
+ table.insert(missing_from_stable, name)
+ end
+ end
+
+ -- Check for stable names not in instructions
+ local inst_name_set = {}
+ for _, name in ipairs(inst_names) do
+ inst_name_set[name] = true
+ end
+
+ for name, _ in pairs(stable_names) do
+ if not inst_name_set[name] then
+ table.insert(extra_in_stable, name)
+ end
+ end
+
+ return missing_from_stable, extra_in_stable
+end
+
+-- Get next available ID
+local function get_next_id(stable_names)
+ local max_id = -1
+ for _, id in pairs(stable_names) do
+ if id > max_id then
+ max_id = id
+ end
+ end
+ return max_id + 1
+end
+
+-- Print usage
+local function print_usage()
+ print("Usage: lua check_instructions.lua check|update [inst_file] [stable_file]")
+ print("Commands:")
+ print(" check - Check bijection and uniqueness (default)")
+ print(" update - Add missing instructions to stable names")
+end
+
+-- Main program
+local function main(args)
+ local command = args[1] or "check"
+ local inst_file = args[2] or "source/slang/slang-ir-insts.lua"
+ local stable_file = args[3] or "source/slang/slang-ir-insts-stable-names.lua"
+
+ -- Validate command
+ local valid_commands = { check = true, update = true }
+ if not valid_commands[command] then
+ print("ERROR: Invalid command: " .. command)
+ print_usage()
+ return 1
+ end
+
+ -- Load data with error handling
+ local ok, insts_or_err = pcall(load_instructions, inst_file)
+ if not ok then
+ print("ERROR: " .. insts_or_err)
+ return 1
+ end
+ local insts = insts_or_err
+
+ ok, stable_names = pcall(load_stable_names, stable_file)
+ if not ok then
+ print("ERROR: " .. stable_names)
+ return 1
+ end
+
+ -- Flatten instruction hierarchy
+ local inst_names = flatten_instructions(insts)
+
+ local has_errors = false
+
+ if command == "check" or command == "all" then
+ print("=== Checking stable names ===")
+
+ -- Check unique IDs
+ local duplicate_ids = check_unique_ids(stable_names)
+ if next(duplicate_ids) then
+ has_errors = true
+ print("ERROR: Duplicate IDs found:")
+ for id, names in pairs(duplicate_ids) do
+ print(string.format(" - ID %d used by: %s", id, table.concat(names, ", ")))
+ end
+ else
+ print("✓ All IDs are unique")
+ end
+
+ -- Check bijection
+ local missing, extra = check_bijection(inst_names, stable_names)
+
+ if #missing > 0 then
+ has_errors = true
+ print(string.format("ERROR: %d instructions missing from stable names:", #missing))
+ for _, name in ipairs(missing) do
+ print(" - " .. name)
+ end
+ else
+ print("✓ All instructions have stable names")
+ end
+
+ if #extra > 0 then
+ print(string.format("WARNING: %d extra entries in stable names (not in instructions):", #extra))
+ for _, name in ipairs(extra) do
+ print(" - " .. name)
+ end
+ else
+ print("✓ No extra entries in stable names")
+ end
+
+ if not has_errors and #extra == 0 then
+ print("✓ Is a bijection")
+ end
+ end
+
+ if command == "update" or command == "all" then
+ print("=== Updating stable names ===")
+
+ -- Don't update if there are errors
+ if has_errors then
+ print("ERROR: Cannot update due to errors in existing stable names")
+ return 1
+ end
+
+ local missing, _ = check_bijection(inst_names, stable_names)
+
+ if #missing > 0 then
+ -- Add missing instructions
+ local next_id = get_next_id(stable_names)
+
+ for _, name in ipairs(missing) do
+ stable_names[name] = next_id
+ next_id = next_id + 1
+ end
+
+ -- Save updated file
+ local ok, err = pcall(save_stable_names, stable_file, stable_names)
+ if not ok then
+ print("ERROR: Failed to save: " .. err)
+ return 1
+ end
+
+ print(string.format("Added %d new instructions to %s", #missing, stable_file))
+ else
+ print("No missing instructions to add")
+ end
+ end
+
+ return has_errors and 1 or 0
+end
+
+-- Run the program
+os.exit(main(arg) or 0)