diff --git a/lang/src/llvm_ir/boxes/builder.hako b/lang/src/llvm_ir/boxes/builder.hako index 68b894c7..017d0818 100644 --- a/lang/src/llvm_ir/boxes/builder.hako +++ b/lang/src/llvm_ir/boxes/builder.hako @@ -7,6 +7,7 @@ using "../instructions/jump.hako" as JumpInst using "../instructions/copy.hako" as CopyInst using "../instructions/phi.hako" as PhiInst using "../instructions/loopform.hako" as LoopFormInst +using "../instructions/mir_call.hako" as MirCallInst // LLVMBuilderBox — 命令構築(v0: const/binop/ret の骨格) static box LLVMBuilderBox { @@ -389,4 +390,22 @@ static box LLVMBuilderBox { emit_loopform(self, loop_id, blocks, condition_vid, options) { return me.lower_loopform(self, loop_id, blocks, condition_vid, options) } + + // Phase v2-C MIR Call 命令(統一Call) + // Args: + // self: static box receiver (implicit) + // callee: calleeオブジェクト {type: "Global|Method|Constructor|...", ...} + // args: 引数配列(ArrayBox of register IDs) + // dst: 結果レジスタID + // options: オプション設定(省略可) + // Returns: + // MIR Call JSON 文字列 + lower_mir_call(self, callee, args, dst, options) { + return MirCallInst.lower_mir_call(self, callee, args, dst, options) + } + + // MIR Call 命令を emit(builder メソッド) + emit_mir_call(self, callee, args, dst, options) { + return me.lower_mir_call(self, callee, args, dst, options) + } } diff --git a/lang/src/llvm_ir/instructions/mir_call.hako b/lang/src/llvm_ir/instructions/mir_call.hako new file mode 100644 index 00000000..80de76e9 --- /dev/null +++ b/lang/src/llvm_ir/instructions/mir_call.hako @@ -0,0 +1,196 @@ +// LLVM MIR Call Instruction Box — Python mir_call.py のHakorune実装 +// 統一Call命令(call/boxcall/externcall/newbox/plugin_invoke/newclosure)を +// JSON形式に変換し、C++バックエンドに渡す +// +// MIR Call は 6種類の callee.type をサポート: +// - Global: グローバル関数呼び出し (print, panic等) +// - Method: Boxメソッド呼び出し (receiver.method()) +// - Constructor: Boxコンストラクタ (new BoxType()) +// - Extern: 外部C ABI関数呼び出し +// - Closure: クロージャ生成 (||{...}) +// - Value: 動的関数値呼び出し (func_value()) +// +// 特徴: +// - CallEmitBox の既存資産を最大活用(60%の機能を提供済み) +// - JSON 構造生成のみ(LLVM IR 生成は C++ backend が担当) +// - Unified architecture(6つの命令を1つに統合) + +using "lang/src/compiler/emit/common/call_emit_box.hako" as CallEmitBox +using "lang/src/compiler/emit/common/json_emit_box.hako" as JsonEmitBox + +static box LLVMMirCallInstructionBox { + + // メインエントリーポイント - Pythonのlower_mir_call()に相当 + // Stage 1: スケルトン実装(既存 CallEmitBox を活用) + // + // Args: + // callee: calleeオブジェクト(MapBox) + // 形式: {type: "Global|Method|Constructor|Extern|Closure|Value", ...} + // args: 引数配列(ArrayBox of register IDs) + // dst: 結果レジスタID + // options: オプション設定(MapBox、将来拡張用) + // + // Returns: + // JSON文字列(MIR Call 命令) + lower_mir_call(self, callee, args, dst, options) { + if callee == null { + return me._mir_call_error_fallback(self, "callee is null") + } + + local callee_type = callee.get("type") + if callee_type == null { + return me._mir_call_error_fallback(self, "callee.type is null") + } + + // Dispatch by callee.type + if callee_type == "Global" { + return me._lower_global(self, callee, args, dst) + } + if callee_type == "Method" { + return me._lower_method(self, callee, args, dst) + } + if callee_type == "Constructor" { + return me._lower_constructor(self, callee, args, dst) + } + if callee_type == "Extern" { + return me._lower_extern(self, callee, args, dst) + } + if callee_type == "Closure" { + return me._lower_closure(self, callee, args, dst) + } + if callee_type == "Value" { + return me._lower_value(self, callee, args, dst) + } + + return me._mir_call_error_fallback(self, "Unknown callee type: " + callee_type) + } + + // Stage 2: Global function call + // 既存の CallEmitBox.make_mir_call_global を活用 + _lower_global(self, callee, args, dst) { + local name = callee.get("name") + if name == null { + return me._mir_call_error_fallback(self, "Global: name is null") + } + local json_obj = CallEmitBox.make_mir_call_global(name, args, dst) + return JsonEmitBox.to_json_instruction(json_obj) + } + + // Stage 2: Method call + // 既存の CallEmitBox.make_mir_call_method を活用 + _lower_method(self, callee, args, dst) { + local method = callee.get("method") + local receiver = callee.get("receiver") + if method == null { + return me._mir_call_error_fallback(self, "Method: method is null") + } + if receiver == null { + return me._mir_call_error_fallback(self, "Method: receiver is null") + } + local json_obj = CallEmitBox.make_mir_call_method(method, receiver, args, dst) + return JsonEmitBox.to_json_instruction(json_obj) + } + + // Stage 2: Constructor call + // 既存の CallEmitBox.make_mir_call_constructor を活用 + _lower_constructor(self, callee, args, dst) { + local box_type = callee.get("box_type") + if box_type == null { + return me._mir_call_error_fallback(self, "Constructor: box_type is null") + } + local json_obj = CallEmitBox.make_mir_call_constructor(box_type, args, dst) + return JsonEmitBox.to_json_instruction(json_obj) + } + + // Stage 3: Extern call + // 既存の CallEmitBox.make_mir_call_extern を活用 + _lower_extern(self, callee, args, dst) { + local name = callee.get("name") + if name == null { + return me._mir_call_error_fallback(self, "Extern: name is null") + } + local json_obj = CallEmitBox.make_mir_call_extern(name, args, dst) + return JsonEmitBox.to_json_instruction(json_obj) + } + + // Stage 4: Closure creation + // TODO: CallEmitBox に make_mir_call_closure を追加する必要あり + _lower_closure(self, callee, args, dst) { + // Placeholder: 将来実装 + local params = callee.get("params") + local captures = callee.get("captures") + + local json = "{" + json = json + "\"op\":\"mir_call\"" + json = json + ",\"dst\":" + dst.toString() + json = json + ",\"callee\":{\"type\":\"Closure\"" + + // params 配列 + if params != null { + json = json + ",\"params\":" + me._array_to_json(self, params) + } + + // captures 配列 + if captures != null { + json = json + ",\"captures\":" + me._array_to_json(self, captures) + } + + json = json + "}" + json = json + ",\"args\":" + me._array_to_json(self, args) + json = json + "}" + + return json + } + + // Stage 4: Value call (dynamic function value) + // TODO: CallEmitBox に make_mir_call_value を追加する必要あり + _lower_value(self, callee, args, dst) { + // Placeholder: 将来実装 + local func_vid = callee.get("value") + if func_vid == null { + return me._mir_call_error_fallback(self, "Value: value is null") + } + + local json = "{" + json = json + "\"op\":\"mir_call\"" + json = json + ",\"dst\":" + dst.toString() + json = json + ",\"callee\":{\"type\":\"Value\",\"value\":" + func_vid.toString() + "}" + json = json + ",\"args\":" + me._array_to_json(self, args) + json = json + "}" + + return json + } + + // Helper: ArrayBox を JSON 配列に変換 + _array_to_json(self, arr) { + if arr == null { + return "[]" + } + local json = "[" + local size = arr.size() + local i = 0 + loop(i < size) { + if i > 0 { + json = json + "," + } + local val = arr.get(i) + json = json + val.toString() + i = i + 1 + } + json = json + "]" + return json + } + + // エラーフォールバック: 空の MIR Call を返す + _mir_call_error_fallback(self, error_msg) { + print("[ERROR] LLVMMirCallInstructionBox: " + error_msg) + return "{\"op\":\"mir_call\",\"dst\":0,\"callee\":{\"type\":\"Global\",\"name\":\"__error__\"},\"args\":[]}" + } + + // デバッグ用: MIR Call 命令の構造を出力 + debug_mir_call(self, callee, args, dst, options) { + local json = me.lower_mir_call(self, callee, args, dst, options) + print("Generated mir_call instruction: " + json) + return json + } +} diff --git a/tests/phase33/smoke/mir_call/global_simple.hako b/tests/phase33/smoke/mir_call/global_simple.hako new file mode 100644 index 00000000..386e920d --- /dev/null +++ b/tests/phase33/smoke/mir_call/global_simple.hako @@ -0,0 +1,45 @@ +// MIR Call Smoke Test 1: Global function call +// Tests basic Global callee type + +using "lang/src/llvm_ir/instructions/mir_call.hako" as MirCallInst + +static box Main { + main() { + print("=== MIR Call Smoke Test 1: global_simple ===") + + // Simulate: print("hello") + local callee = new MapBox() + callee.set("type", "Global") + callee.set("name", "print") + + local args = new ArrayBox() + args.push(1) // register ID 1 + + // Generate mir_call JSON + local json = MirCallInst.lower_mir_call(null, callee, args, 2, null) + + // Verify JSON structure + local has_mir_call = json.indexOf("\"op\":\"mir_call\"") + if has_mir_call < 0 { + print("ERROR: op not found") + return 1 + } + + local has_global = json.indexOf("\"type\":\"Global\"") + if has_global < 0 { + print("ERROR: Global type not found") + return 1 + } + + local has_name = json.indexOf("\"name\":\"print\"") + if has_name < 0 { + print("ERROR: function name not found") + return 1 + } + + print("✓ PASS: global_simple mir_call generated") + print("Note: Actual execution requires C++ backend implementation") + + return 0 + } +} diff --git a/tests/phase33/unit/mir_call/test_basic.hako b/tests/phase33/unit/mir_call/test_basic.hako new file mode 100644 index 00000000..c83da433 --- /dev/null +++ b/tests/phase33/unit/mir_call/test_basic.hako @@ -0,0 +1,263 @@ +// Phase v2-C: MIR Call Instruction Unit Tests +// Tests basic mir_call.hako functionality with 6 callee types + +using "lang/src/llvm_ir/instructions/mir_call.hako" as MirCallInst + +static box Main { + main() { + print("=== Phase v2-C MIR Call Unit Tests ===\n") + + local total_tests = 0 + local passed_tests = 0 + + // Test 1: Global function call + print("[Test 1] Global function call") + total_tests = total_tests + 1 + if me.test_global_call() == 0 { + passed_tests = passed_tests + 1 + print("✓ PASS\n") + } else { + print("✗ FAIL\n") + } + + // Test 2: Method call + print("[Test 2] Method call") + total_tests = total_tests + 1 + if me.test_method_call() == 0 { + passed_tests = passed_tests + 1 + print("✓ PASS\n") + } else { + print("✗ FAIL\n") + } + + // Test 3: Constructor call + print("[Test 3] Constructor call") + total_tests = total_tests + 1 + if me.test_constructor_call() == 0 { + passed_tests = passed_tests + 1 + print("✓ PASS\n") + } else { + print("✗ FAIL\n") + } + + // Test 4: Extern call + print("[Test 4] Extern call") + total_tests = total_tests + 1 + if me.test_extern_call() == 0 { + passed_tests = passed_tests + 1 + print("✓ PASS\n") + } else { + print("✗ FAIL\n") + } + + // Test 5: Closure creation + print("[Test 5] Closure creation") + total_tests = total_tests + 1 + if me.test_closure_call() == 0 { + passed_tests = passed_tests + 1 + print("✓ PASS\n") + } else { + print("✗ FAIL\n") + } + + // Test 6: Value call + print("[Test 6] Value call") + total_tests = total_tests + 1 + if me.test_value_call() == 0 { + passed_tests = passed_tests + 1 + print("✓ PASS\n") + } else { + print("✗ FAIL\n") + } + + // Summary + print("=== Summary ===") + print("Total: " + total_tests.toString() + " tests") + print("Passed: " + passed_tests.toString() + " tests") + print("Failed: " + (total_tests - passed_tests).toString() + " tests") + + if passed_tests == total_tests { + print("\n✓ ALL TESTS PASSED") + return 0 + } else { + print("\n✗ SOME TESTS FAILED") + return 1 + } + } + + // Test 1: Global function call + test_global_call() { + local callee = new MapBox() + callee.set("type", "Global") + callee.set("name", "print") + + local args = new ArrayBox() + args.push(1) // arg register ID + + local result = MirCallInst.lower_mir_call(null, callee, args, 2, null) + + // Verify JSON contains expected fields + local has_op = result.indexOf("\"op\":\"mir_call\"") + if has_op < 0 { + print(" ERROR: op not found") + return 1 + } + + local has_global = result.indexOf("\"type\":\"Global\"") + if has_global < 0 { + print(" ERROR: Global type not found") + return 1 + } + + local has_name = result.indexOf("\"name\":\"print\"") + if has_name < 0 { + print(" ERROR: name not found") + return 1 + } + + return 0 + } + + // Test 2: Method call + test_method_call() { + local callee = new MapBox() + callee.set("type", "Method") + callee.set("method", "get") + callee.set("receiver", 3) + + local args = new ArrayBox() + args.push(4) // arg register ID + + local result = MirCallInst.lower_mir_call(null, callee, args, 5, null) + + local has_method = result.indexOf("\"type\":\"Method\"") + if has_method < 0 { + print(" ERROR: Method type not found") + return 1 + } + + local has_method_name = result.indexOf("\"method\":\"get\"") + if has_method_name < 0 { + print(" ERROR: method name not found") + return 1 + } + + local has_receiver = result.indexOf("\"receiver\":3") + if has_receiver < 0 { + print(" ERROR: receiver not found") + return 1 + } + + return 0 + } + + // Test 3: Constructor call + test_constructor_call() { + local callee = new MapBox() + callee.set("type", "Constructor") + callee.set("box_type", "ArrayBox") + + local args = new ArrayBox() + + local result = MirCallInst.lower_mir_call(null, callee, args, 6, null) + + local has_constructor = result.indexOf("\"type\":\"Constructor\"") + if has_constructor < 0 { + print(" ERROR: Constructor type not found") + return 1 + } + + local has_box_type = result.indexOf("\"box_type\":\"ArrayBox\"") + if has_box_type < 0 { + print(" ERROR: box_type not found") + return 1 + } + + return 0 + } + + // Test 4: Extern call + test_extern_call() { + local callee = new MapBox() + callee.set("type", "Extern") + callee.set("name", "malloc") + + local args = new ArrayBox() + args.push(7) + + local result = MirCallInst.lower_mir_call(null, callee, args, 8, null) + + local has_extern = result.indexOf("\"type\":\"Extern\"") + if has_extern < 0 { + print(" ERROR: Extern type not found") + return 1 + } + + local has_name = result.indexOf("\"name\":\"malloc\"") + if has_name < 0 { + print(" ERROR: extern name not found") + return 1 + } + + return 0 + } + + // Test 5: Closure creation + test_closure_call() { + local callee = new MapBox() + callee.set("type", "Closure") + + local params = new ArrayBox() + params.push(9) + params.push(10) + callee.set("params", params) + + local captures = new ArrayBox() + captures.push(11) + callee.set("captures", captures) + + local args = new ArrayBox() + + local result = MirCallInst.lower_mir_call(null, callee, args, 12, null) + + local has_closure = result.indexOf("\"type\":\"Closure\"") + if has_closure < 0 { + print(" ERROR: Closure type not found") + return 1 + } + + local has_params = result.indexOf("\"params\"") + if has_params < 0 { + print(" ERROR: params not found") + return 1 + } + + return 0 + } + + // Test 6: Value call + test_value_call() { + local callee = new MapBox() + callee.set("type", "Value") + callee.set("value", 13) + + local args = new ArrayBox() + args.push(14) + + local result = MirCallInst.lower_mir_call(null, callee, args, 15, null) + + local has_value = result.indexOf("\"type\":\"Value\"") + if has_value < 0 { + print(" ERROR: Value type not found") + return 1 + } + + local has_value_id = result.indexOf("\"value\":13") + if has_value_id < 0 { + print(" ERROR: value ID not found") + return 1 + } + + return 0 + } +}