metal: GPU protocol + MetalGPU renders MSL triangle on iOS

Phase 8 step 3a of the Metal renderer port:

- New library/modules/gpu/ with types.sx (handles + ClearColor +
  TextureFormat enum), api.sx (GPU :: protocol { ... } covering the
  lifecycle / per-frame / resource / per-draw surface), and metal.sx
  (MetalGPU backend implementing the protocol against CAMetalLayer).
  Resource handles are 1-based indices into backend List(*void) tables.
  MTL aggregates >16 bytes (MTLRegion, MTLScissorRect) pass via *T to
  match arm64 Apple's indirect-by-reference ABI; MTLClearColor + CGSize
  go through the HFA path as direct fn-pointer casts on objc_msgSend.

- UIKitPlatform got a gpu_mode: GpuMode toggle + sibling SxMetalView
  class registration. In metal mode init skips EAGL context, the
  did_finish_launching IMP skips the EAGL drawable-properties dict,
  layoutSubviews reads the layer's bounds * dpi_scale into pixel_w/h
  instead of allocating a GL renderbuffer, and end_frame is a no-op
  (the MetalGPU owns its own present).

- examples/63-metal-clear.sx verifies the pipeline end-to-end on iOS
  sim — compiles a pass-through MSL shader (packed_float2/packed_float4
  to avoid alignment padding), uploads 3 vertices, draws a colored
  triangle on a dark-blue clear.

Compiler fixes (filed-and-fixed in this branch):

- inline if X { return E; } followed by a fall-through final expression
  no longer emits two terminators into the same basic block. Verified
  by examples/83-inline-if-return-fallthrough.sx.

- Top-level type alias Name :: u32; now resolves correctly as the type
  annotation on a global variable (was treated as ptr {}, breaking
  comparisons + initializers). Verified by examples/84-global-type-alias.sx.

Issue->feature promotion:

- 16 historical examples/issue-NNNN.sx repros now confirmed-fixed and
  renamed to focused feature names (67-82). Each gains a
  tests/expected/*.txt + .exit pair so the regression suite covers them.

- 5 stale issue repros deleted (subsumed by broader tests).

Regression suite: 68 passing, 0 failed. macOS chess builds + runs; wasm
chess builds; iOS sim GLES chess still renders the full board; iOS sim
Metal demo renders the triangle.
This commit is contained in:
agra
2026-05-17 19:36:37 +03:00
parent 2ff24e29cc
commit a938c4f900
66 changed files with 1248 additions and 376 deletions

View File

@@ -2848,19 +2848,29 @@ pub const LLVMEmitter = struct {
}
fn emitConstAggregate(self: *LLVMEmitter, agg: []const ir_inst.ConstantValue, llvm_ty: c.LLVMTypeRef) c.LLVMValueRef {
const elem_ty = c.LLVMGetElementType(llvm_ty);
const kind = c.LLVMGetTypeKind(llvm_ty);
const is_struct = kind == c.LLVMStructTypeKind;
const n: c_uint = @intCast(agg.len);
const vals = self.alloc.alloc(c.LLVMValueRef, agg.len) catch return c.LLVMConstNull(llvm_ty);
defer self.alloc.free(vals);
for (agg, 0..) |cv, i| {
const elem_ty = if (is_struct)
c.LLVMStructGetTypeAtIndex(llvm_ty, @intCast(i))
else
c.LLVMGetElementType(llvm_ty);
vals[i] = switch (cv) {
.int => |v| c.LLVMConstInt(elem_ty, @bitCast(v), 1),
.float => |v| c.LLVMConstReal(elem_ty, v),
.boolean => |v| c.LLVMConstInt(elem_ty, @intFromBool(v), 0),
.string => |sid| self.emitConstStringGlobal(self.ir_mod.types.getString(sid)),
.aggregate => |inner| self.emitConstAggregate(inner, elem_ty),
else => c.LLVMConstNull(elem_ty),
};
}
if (is_struct) {
return c.LLVMConstNamedStruct(llvm_ty, vals.ptr, n);
}
const elem_ty = c.LLVMGetElementType(llvm_ty);
return c.LLVMConstArray(elem_ty, vals.ptr, n);
}