From 259f00825899899baa76767c73beddc6fea9e4a3 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Wed, 12 Aug 2026 01:34:42 +0800 Subject: [PATCH] cmd/llvmplugin: test X86 ABI0 entry argument maps --- src/cmd/llvmplugin/CMakeLists.txt | 23 +++ .../testdata/check-x86-abi0-entry-args.py | 139 ++++++++++++++++++ .../testdata/x86-abi0-entry-args.ll | 13 ++ 3 files changed, 175 insertions(+) create mode 100644 src/cmd/llvmplugin/testdata/check-x86-abi0-entry-args.py create mode 100644 src/cmd/llvmplugin/testdata/x86-abi0-entry-args.ll diff --git a/src/cmd/llvmplugin/CMakeLists.txt b/src/cmd/llvmplugin/CMakeLists.txt index c30a1d37f95f6e..b710abaaabc318 100644 --- a/src/cmd/llvmplugin/CMakeLists.txt +++ b/src/cmd/llvmplugin/CMakeLists.txt @@ -350,6 +350,17 @@ if(BUILD_TESTING) "${CMAKE_CURRENT_SOURCE_DIR}/testdata/aarch64-frame.ll" ) + add_test( + NAME GoALLCStatepoints.X86ABI0EntryArgsGoObj + COMMAND + "${GOALLC_LLC_EXECUTABLE}" + "-load-pass-plugin=$" + -verify-machineinstrs + -filetype=obj + -o "${CMAKE_CURRENT_BINARY_DIR}/x86-abi0-entry-args.goobj" + "${CMAKE_CURRENT_SOURCE_DIR}/testdata/x86-abi0-entry-args.ll" + ) + add_test( NAME GoALLCStatepoints.MultipleCallsRewrite COMMAND @@ -443,6 +454,18 @@ if(BUILD_TESTING) DEPENDS GoALLCStatepoints.AArch64FrameGoObj ) + add_test( + NAME GoALLCStatepoints.X86ABI0EntryArgsObjView + COMMAND + "${Python3_EXECUTABLE}" + "${CMAKE_CURRENT_SOURCE_DIR}/testdata/check-x86-abi0-entry-args.py" + --objview "${GOALLC_OBJVIEW_EXECUTABLE}" + --object "${CMAKE_CURRENT_BINARY_DIR}/x86-abi0-entry-args.goobj" + ) + set_tests_properties(GoALLCStatepoints.X86ABI0EntryArgsObjView PROPERTIES + DEPENDS GoALLCStatepoints.X86ABI0EntryArgsGoObj + ) + add_test( NAME GoALLCStatepoints.ConditionalRelocationObjView COMMAND diff --git a/src/cmd/llvmplugin/testdata/check-x86-abi0-entry-args.py b/src/cmd/llvmplugin/testdata/check-x86-abi0-entry-args.py new file mode 100644 index 00000000000000..54ef36640633be --- /dev/null +++ b/src/cmd/llvmplugin/testdata/check-x86-abi0-entry-args.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +import argparse +import json +import subprocess +import sys + + +FUNCTION = "abi0_pointer_arguments" + + +def fail(message): + raise RuntimeError(message) + + +def only(items, predicate, description): + matches = [item for item in items if predicate(item)] + if len(matches) != 1: + fail(f"found {len(matches)} {description}, want 1") + return matches[0] + + +def reference_name(obj, target): + if target["pkg_kind"] != "none": + fail(f"cannot resolve non-reference target: {target}") + reference = only( + obj["references"], + lambda item: ( + item["class"] == "nonpackage_reference" + and item["class_index"] == target["sym_index"] + ), + f"references for target {target}", + ) + return reference["name"] + + +def stack_map(metadata, kind): + return only( + metadata["funcdata"], + lambda item: item["kind"] == kind, + f"{kind} tables", + )["stack_map"] + + +def bitmap_bits(stack_map, index): + return set(stack_map["bitmaps"][index]["set_bits"] or []) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--objview", required=True) + parser.add_argument("--object", required=True) + args = parser.parse_args() + + result = subprocess.run( + [args.objview, "-json", args.object], + check=True, + stdout=subprocess.PIPE, + text=True, + ) + document = json.loads(result.stdout) + obj = only( + [ + member["go_object"] + for member in document["members"] + if member.get("go_object") is not None + ], + lambda item: True, + "Go objects", + ) + symbol = only( + obj["symbols"], + lambda item: item["name"] == FUNCTION, + f"{FUNCTION} symbols", + ) + metadata = symbol.get("function") + if metadata is None: + fail(f"{FUNCTION} has no function metadata") + if metadata["info"]["args"] != 24: + fail(f"{FUNCTION} args={metadata['info']['args']}, want 24") + + args_maps = stack_map(metadata, "args_pointer_maps") + locals_maps = stack_map(metadata, "locals_pointer_maps") + if args_maps["count"] != 2 or args_maps["num_bits"] != 3: + fail(f"unexpected args stack-map dimensions: {args_maps}") + if locals_maps["count"] != 2: + fail(f"unexpected locals stack-map dimensions: {locals_maps}") + + entry_args = bitmap_bits(args_maps, 0) + ordinary_args = bitmap_bits(args_maps, 1) + entry_locals = bitmap_bits(locals_maps, 0) + ordinary_locals = bitmap_bits(locals_maps, 1) + if entry_args != {0, 1, 2}: + fail(f"entry args={sorted(entry_args)}, want [0, 1, 2]") + if ordinary_args or entry_locals or ordinary_locals: + fail( + "non-entry roots are not empty: " + f"ordinary-args={sorted(ordinary_args)}, " + f"entry-locals={sorted(entry_locals)}, " + f"ordinary-locals={sorted(ordinary_locals)}" + ) + + queries = metadata["stack_map_queries"] + if len(queries) != 2: + fail(f"unexpected call queries: {queries}") + morestack_query = only( + queries, + lambda item: reference_name(obj, item["target"]) + == "runtime.morestack_noctxt", + "morestack queries", + ) + call_query = only( + queries, + lambda item: reference_name(obj, item["target"]) + == "use_three_pointers", + "ordinary call queries", + ) + if morestack_query["stack_map_index"] != 0: + fail(f"morestack does not select entry map: {morestack_query}") + if call_query["stack_map_index"] != 1: + fail(f"ordinary call does not select map 1: {call_query}") + + print( + f"{FUNCTION}: args={metadata['info']['args']} " + f"entry-args={sorted(entry_args)} ordinary-roots=[]" + ) + + +if __name__ == "__main__": + try: + main() + except ( + KeyError, + RuntimeError, + subprocess.CalledProcessError, + json.JSONDecodeError, + ) as error: + print(f"check-x86-abi0-entry-args: {error}", file=sys.stderr) + sys.exit(1) diff --git a/src/cmd/llvmplugin/testdata/x86-abi0-entry-args.ll b/src/cmd/llvmplugin/testdata/x86-abi0-entry-args.ll new file mode 100644 index 00000000000000..56027cab46c1f8 --- /dev/null +++ b/src/cmd/llvmplugin/testdata/x86-abi0-entry-args.ll @@ -0,0 +1,13 @@ +target triple = "x86_64-unknown-linux-goobj" + +declare goabiinternal void @use_three_pointers(ptr, ptr, ptr) + +define goabi0 void @abi0_pointer_arguments( + ptr %first, ptr %second, ptr %third) #0 gc "goallc" { +entry: + call goabiinternal void @use_three_pointers( + ptr %first, ptr %second, ptr %third) + ret void +} + +attributes #0 = { "frame-pointer"="non-leaf" "go-stack-growth-statepoint" }