test(asm): reject symbol "s" operands cleanly + lock (symbol-op prep)
A symbol operand (constraint "s") feeds a function/global symbol whose mangled name the template emits — enabling a DIRECT `bl %[fn]` (one fewer indirection than register-indirect `blr`). Until now `"s" = fn` fell through to emit and produced an LLVM-verifier crash (param type mismatch). Reject it at lowering with a clear diagnostic instead, and lock that with examples/1656-platform-asm-symbol-operand.sx. The next commit implements it and flips the example to run (→ 42).
This commit is contained in:
24
examples/1656-platform-asm-symbol-operand.sx
Normal file
24
examples/1656-platform-asm-symbol-operand.sx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// ASM stream — symbol operand (`"s"`): feed a function/global SYMBOL into the
|
||||||
|
// template so a DIRECT `bl %[fn]` (PC-relative, one fewer indirection than a
|
||||||
|
// register-indirect `blr`) branches straight to it, with the platform-mangled
|
||||||
|
// name emitted by the backend (so the template stays portable — no hardcoded
|
||||||
|
// `_` underscore). Not yet implemented — rejected at lowering for now. The next
|
||||||
|
// commit implements it and flips this example to run (sx → asm → sx, → 42).
|
||||||
|
cb :: (n: i64) -> i64 export "cb" { return n + 1; }
|
||||||
|
|
||||||
|
tramp :: (n: i64) -> i64 {
|
||||||
|
return asm volatile {
|
||||||
|
#string ASM
|
||||||
|
stp x29, x30, [sp, #-16]!
|
||||||
|
mov x0, %[arg]
|
||||||
|
bl %[fn]
|
||||||
|
mov %[res], x0
|
||||||
|
ldp x29, x30, [sp], #16
|
||||||
|
ASM,
|
||||||
|
[res] "=r" -> i64,
|
||||||
|
[arg] "r" = n,
|
||||||
|
[fn] "s" = cb, // symbol operand → direct `bl _cb`
|
||||||
|
clobbers(.x0, .x30, .memory),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
main :: () -> i64 { return tramp(41); }
|
||||||
1
examples/expected/1656-platform-asm-symbol-operand.exit
Normal file
1
examples/expected/1656-platform-asm-symbol-operand.exit
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
29
examples/expected/1656-platform-asm-symbol-operand.stderr
Normal file
29
examples/expected/1656-platform-asm-symbol-operand.stderr
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
error: symbol asm operands (`"s"`) are not yet implemented
|
||||||
|
--> examples/1656-platform-asm-symbol-operand.sx:10:12
|
||||||
|
|
|
||||||
|
10 | return asm volatile {
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
11 | #string ASM
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
12 | stp x29, x30, [sp, #-16]!
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
13 | mov x0, %[arg]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
14 | bl %[fn]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
15 | mov %[res], x0
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
16 | ldp x29, x30, [sp], #16
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
17 | ASM,
|
||||||
|
| ^^^^
|
||||||
|
18 | [res] "=r" -> i64,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
19 | [arg] "r" = n,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
20 | [fn] "s" = cb, // symbol operand → direct `bl _cb`
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
21 | clobbers(.x0, .x30, .memory),
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
22 | };
|
||||||
|
| ^^^^^
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -2366,7 +2366,17 @@ pub fn lowerAsmExpr(self: *Lowering, ae: *const ast.AsmExpr, span: ast.Span) Ref
|
|||||||
var operand_ref: Ref = Ref.none;
|
var operand_ref: Ref = Ref.none;
|
||||||
var out_ty: TypeId = .void;
|
var out_ty: TypeId = .void;
|
||||||
switch (op.role) {
|
switch (op.role) {
|
||||||
.input => operand_ref = self.lowerExpr(op.payload),
|
.input => {
|
||||||
|
// Symbol operands (constraint `"s"`) — feed a function/global
|
||||||
|
// SYMBOL whose mangled name the template emits (e.g. a direct
|
||||||
|
// `bl %[fn]`). Not yet implemented; reject loudly rather than
|
||||||
|
// emit invalid IR (an LLVM-verifier crash). [Phase: symbol ops.]
|
||||||
|
if (std.mem.eql(u8, op.constraint, "s")) {
|
||||||
|
diags.addFmt(.err, span, "symbol asm operands (`\"s\"`) are not yet implemented", .{});
|
||||||
|
return self.emitPlaceholder("inline_asm");
|
||||||
|
}
|
||||||
|
operand_ref = self.lowerExpr(op.payload);
|
||||||
|
},
|
||||||
.out_value => out_ty = self.resolveTypeWithBindings(op.payload),
|
.out_value => out_ty = self.resolveTypeWithBindings(op.payload),
|
||||||
.out_place => {
|
.out_place => {
|
||||||
// Read-write (`+`) outputs tie an input to the output and seed
|
// Read-write (`+`) outputs tie an input to the output and seed
|
||||||
|
|||||||
Reference in New Issue
Block a user