Skip to content

Commit c663d3a

Browse files
committed
ctxreg: disable x86 regs
1 parent dcc8fcc commit c663d3a

4 files changed

Lines changed: 39 additions & 50 deletions

File tree

doc/closure.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,15 @@ Closure bodies accept an explicit ctx parameter and use it as the env base.
6868

6969
| GOARCH | Register | Notes |
7070
|---|---|---|
71-
| amd64 | mm0 | use `-msse2` to free MMX |
72-
| 386 | mm0 | use `-msse2` to free MMX |
71+
| amd64 | - | ctx register disabled (x87/mm0 aliasing with `long double`) |
72+
| 386 | - | ctx register disabled (x87/mm0 aliasing with `long double`) |
7373
| arm64 | x26 | reserved via clang target-feature |
7474
| riscv64 | x27 | reserved via clang target-feature |
7575
| wasm | - | conditional ctx param |
7676
| arm | - | conditional ctx param |
7777

7878
Native builds reserve the ctx reg via clang target-feature `+reserve-<reg>`
79-
(arm64/riscv64). For caller-saved x86, inline asm uses a memory clobber;
80-
callee-saved targets do not.
79+
(arm64/riscv64). Callee-saved targets do not require a memory clobber.
8180

8281
## Covered Scenarios
8382

internal/ctxreg/ctxreg.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ type Info struct {
77
}
88

99
var table = map[string]Info{
10-
"amd64": {Name: "mm0", Constraint: "{mm0}"},
1110
"arm64": {Name: "x26", Constraint: "{x26}"},
12-
"386": {Name: "mm0", Constraint: "{mm0}"},
1311
"riscv64": {Name: "x27", Constraint: "{x27}"},
1412
"riscv32": {Name: "x27", Constraint: "{x27}"},
1513
}
@@ -25,16 +23,10 @@ func ReserveFlags(goarch string) []string {
2523
if info.Name == "" {
2624
return nil
2725
}
28-
switch goarch {
29-
case "amd64", "386":
30-
// Ensure floating point uses XMM so MMX regs remain free for ctx.
31-
return []string{"-msse2"}
32-
default:
33-
// Use target-feature to reserve the register across backends.
34-
// Suppress warning about clobbering reserved registers in inline asm.
35-
return []string{
36-
"-Xclang", "-target-feature", "-Xclang", "+reserve-" + info.Name,
37-
"-Wno-inline-asm",
38-
}
26+
// Use target-feature to reserve the register across backends.
27+
// Suppress warning about clobbering reserved registers in inline asm.
28+
return []string{
29+
"-Xclang", "-target-feature", "-Xclang", "+reserve-" + info.Name,
30+
"-Wno-inline-asm",
3931
}
4032
}

ssa/ssa_test.go

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ _llgo_0:
226226
}
227227

228228
func TestCallClosureDynamic(t *testing.T) {
229-
prog := NewProgram(&Target{GOARCH: "amd64"})
229+
prog := NewProgram(&Target{GOARCH: "arm64"})
230230
pkg := prog.NewPackage("bar", "foo/bar")
231231

232232
params := types.NewTuple(types.NewVar(0, nil, "x", types.Typ[types.Int]))
@@ -248,7 +248,7 @@ define i64 @caller({ ptr, ptr } %0, i64 %1) {
248248
_llgo_0:
249249
%2 = extractvalue { ptr, ptr } %0, 1
250250
%3 = extractvalue { ptr, ptr } %0, 0
251-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %2)
251+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %2)
252252
%4 = call i64 %3(i64 %1)
253253
ret i64 %4
254254
}
@@ -338,7 +338,7 @@ func TestCvtClosureDropsRecv(t *testing.T) {
338338
}
339339

340340
func TestIfaceMethodClosureCallIR(t *testing.T) {
341-
prog := NewProgram(&Target{GOARCH: "amd64"})
341+
prog := NewProgram(&Target{GOARCH: "arm64"})
342342
prog.SetRuntime(func() *types.Package {
343343
fset := token.NewFileSet()
344344
imp := packages.NewImporter(fset)
@@ -382,7 +382,7 @@ _llgo_0:
382382
%6 = insertvalue { ptr, ptr } %5, ptr %1, 1
383383
%7 = extractvalue { ptr, ptr } %6, 0
384384
%8 = extractvalue { ptr, ptr } %6, 1
385-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %8)
385+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %8)
386386
%9 = call i64 (ptr, ...) %7(ptr %8, i64 100, i64 200)
387387
ret i64 %9
388388
}
@@ -398,11 +398,11 @@ func TestCtxRegisterDefinitions(t *testing.T) {
398398
wantName string
399399
wantConstr string
400400
}{
401-
{"linux", "amd64", "mm0", "{mm0}"},
401+
{"linux", "amd64", "", ""},
402402
{"linux", "arm64", "x26", "{x26}"},
403403
{"darwin", "arm64", "x26", "{x26}"},
404404
{"linux", "arm", "", ""},
405-
{"linux", "386", "mm0", "{mm0}"},
405+
{"linux", "386", "", ""},
406406
{"linux", "riscv64", "x27", "{x27}"},
407407
{"linux", "riscv32", "x27", "{x27}"},
408408
{"js", "wasm", "", ""},
@@ -420,7 +420,7 @@ func TestCtxRegisterDefinitions(t *testing.T) {
420420
}
421421

422422
func TestCtxRegisterFallback(t *testing.T) {
423-
tests := []string{"wasm"}
423+
tests := []string{"amd64", "386", "wasm"}
424424
for _, goarch := range tests {
425425
reg := (&Target{GOARCH: goarch}).CtxRegister()
426426
if reg.Name != "" || reg.Constraint != "" {
@@ -430,7 +430,7 @@ func TestCtxRegisterFallback(t *testing.T) {
430430
}
431431

432432
func TestWriteReadCtxRegIR(t *testing.T) {
433-
prog := NewProgram(&Target{GOARCH: "amd64"})
433+
prog := NewProgram(&Target{GOARCH: "arm64"})
434434
pkg := prog.NewPackage("test", "test")
435435
fn := pkg.NewFunc("test_ctx_reg", NoArgsNoRet, InGo)
436436
b := fn.MakeBody(1)
@@ -441,10 +441,10 @@ func TestWriteReadCtxRegIR(t *testing.T) {
441441
b.Return()
442442

443443
ir := pkg.String()
444-
if !strings.Contains(ir, `asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"`) {
444+
if !strings.Contains(ir, `asm sideeffect "mov x26, $0", "r,~{x26}"`) {
445445
t.Errorf("expected ctx write asm in IR:\n%s", ir)
446446
}
447-
if !strings.Contains(ir, `asm sideeffect "movq %mm0, $0", "=r,~{memory}"`) {
447+
if !strings.Contains(ir, `asm sideeffect "mov $0, x26", "=r"`) {
448448
t.Errorf("expected ctx read asm in IR:\n%s", ir)
449449
}
450450
}
@@ -479,7 +479,7 @@ func TestWriteReadCtxRegUnsupported(t *testing.T) {
479479
}
480480

481481
func TestCallClosureViaRegister(t *testing.T) {
482-
prog := NewProgram(&Target{GOARCH: "amd64"})
482+
prog := NewProgram(&Target{GOARCH: "arm64"})
483483
pkg := prog.NewPackage("bar", "foo/bar")
484484

485485
params := types.NewTuple(types.NewVar(0, nil, "x", types.Typ[types.Int]))
@@ -502,15 +502,15 @@ define i64 @caller({ ptr, ptr } %0, i64 %1) {
502502
_llgo_0:
503503
%2 = extractvalue { ptr, ptr } %0, 1
504504
%3 = extractvalue { ptr, ptr } %0, 0
505-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %2)
505+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %2)
506506
%4 = call i64 %3(i64 %1)
507507
ret i64 %4
508508
}
509509
`)
510510
}
511511

512512
func TestClosureFunctionReadsCtxFromReg(t *testing.T) {
513-
prog := NewProgram(&Target{GOARCH: "amd64"})
513+
prog := NewProgram(&Target{GOARCH: "arm64"})
514514
prog.SetRuntime(func() *types.Package {
515515
fset := token.NewFileSet()
516516
imp := packages.NewImporter(fset)
@@ -538,7 +538,7 @@ source_filename = "foo/bar"
538538
539539
define i64 @inner(i64 %0) {
540540
_llgo_0:
541-
%1 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
541+
%1 = call ptr asm sideeffect "mov $0, x26", "=r"()
542542
%2 = load { i64 }, ptr %1, align 4
543543
%3 = extractvalue { i64 } %2, 0
544544
%4 = add i64 %3, %0
@@ -595,7 +595,7 @@ _llgo_3: ; preds = %_llgo_2, %_llgo_1
595595
}
596596

597597
func TestMakeClosureWithBindings(t *testing.T) {
598-
prog := NewProgram(&Target{GOARCH: "amd64"})
598+
prog := NewProgram(&Target{GOARCH: "arm64"})
599599
prog.SetRuntime(func() *types.Package {
600600
fset := token.NewFileSet()
601601
imp := packages.NewImporter(fset)
@@ -634,7 +634,7 @@ source_filename = "foo/bar"
634634
635635
define i64 @inner(i64 %0) {
636636
_llgo_0:
637-
%1 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
637+
%1 = call ptr asm sideeffect "mov $0, x26", "=r"()
638638
%2 = load { i64 }, ptr %1, align 4
639639
%3 = extractvalue { i64 } %2, 0
640640
%4 = add i64 %3, %0
@@ -656,7 +656,7 @@ declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64)
656656

657657
// TestClosureIIFEIR verifies IR for immediately invoked function expression (IIFE).
658658
func TestClosureIIFEIR(t *testing.T) {
659-
prog := NewProgram(&Target{GOARCH: "amd64"})
659+
prog := NewProgram(&Target{GOARCH: "arm64"})
660660
prog.SetRuntime(func() *types.Package {
661661
fset := token.NewFileSet()
662662
imp := packages.NewImporter(fset)
@@ -693,7 +693,7 @@ source_filename = "test"
693693
694694
define i64 @iife_inner(i64 %0) {
695695
_llgo_0:
696-
%1 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
696+
%1 = call ptr asm sideeffect "mov $0, x26", "=r"()
697697
%2 = load { i64 }, ptr %1, align 4
698698
%3 = extractvalue { i64 } %2, 0
699699
%4 = add i64 %3, %0
@@ -708,7 +708,7 @@ _llgo_0:
708708
%3 = insertvalue { ptr, ptr } { ptr @iife_inner, ptr undef }, ptr %1, 1
709709
%4 = extractvalue { ptr, ptr } %3, 1
710710
%5 = extractvalue { ptr, ptr } %3, 0
711-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %4)
711+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %4)
712712
%6 = call i64 %5(i64 5)
713713
ret i64 %6
714714
}
@@ -719,7 +719,7 @@ declare ptr @"github.com/goplus/llgo/runtime/internal/runtime.AllocU"(i64)
719719

720720
// TestClosureAsParamIR verifies IR for closure passed as function parameter.
721721
func TestClosureAsParamIR(t *testing.T) {
722-
prog := NewProgram(&Target{GOARCH: "amd64"})
722+
prog := NewProgram(&Target{GOARCH: "arm64"})
723723
pkg := prog.NewPackage("test", "test")
724724

725725
closureParams := types.NewTuple(types.NewVar(0, nil, "n", types.Typ[types.Int]))
@@ -744,11 +744,11 @@ define i64 @applyTwice({ ptr, ptr } %0, i64 %1) {
744744
_llgo_0:
745745
%2 = extractvalue { ptr, ptr } %0, 1
746746
%3 = extractvalue { ptr, ptr } %0, 0
747-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %2)
747+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %2)
748748
%4 = call i64 %3(i64 %1)
749749
%5 = extractvalue { ptr, ptr } %0, 1
750750
%6 = extractvalue { ptr, ptr } %0, 0
751-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %5)
751+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %5)
752752
%7 = call i64 %6(i64 %4)
753753
ret i64 %7
754754
}
@@ -757,7 +757,7 @@ _llgo_0:
757757

758758
// TestDeferClosureIR verifies that closure body reads ctx from register.
759759
func TestDeferClosureIR(t *testing.T) {
760-
prog := NewProgram(&Target{GOARCH: "amd64"})
760+
prog := NewProgram(&Target{GOARCH: "arm64"})
761761
prog.SetRuntime(func() *types.Package {
762762
fset := token.NewFileSet()
763763
imp := packages.NewImporter(fset)
@@ -781,7 +781,7 @@ source_filename = "test"
781781
782782
define void @defer_body() {
783783
_llgo_0:
784-
%0 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
784+
%0 = call ptr asm sideeffect "mov $0, x26", "=r"()
785785
%1 = load { i64 }, ptr %0, align 4
786786
%2 = extractvalue { i64 } %1, 0
787787
ret void
@@ -791,7 +791,7 @@ _llgo_0:
791791

792792
// TestGoClosureIR verifies that closure body reads ctx from register.
793793
func TestGoClosureIR(t *testing.T) {
794-
prog := NewProgram(&Target{GOARCH: "amd64"})
794+
prog := NewProgram(&Target{GOARCH: "arm64"})
795795
prog.SetRuntime(func() *types.Package {
796796
fset := token.NewFileSet()
797797
imp := packages.NewImporter(fset)
@@ -815,7 +815,7 @@ source_filename = "test"
815815
816816
define void @goroutine_body() {
817817
_llgo_0:
818-
%0 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
818+
%0 = call ptr asm sideeffect "mov $0, x26", "=r"()
819819
%1 = load { i64 }, ptr %0, align 4
820820
%2 = extractvalue { i64 } %1, 0
821821
ret void
@@ -825,7 +825,7 @@ _llgo_0:
825825

826826
// TestGoRoutineWrapperCtxIR verifies goroutine wrapper sets ctx register before calling closure.
827827
func TestGoRoutineWrapperCtxIR(t *testing.T) {
828-
target := &Target{GOARCH: "amd64"}
828+
target := &Target{GOARCH: "arm64"}
829829
prog := NewProgram(target)
830830
prog.SetRuntime(func() *types.Package {
831831
fset := token.NewFileSet()
@@ -861,7 +861,7 @@ source_filename = "test"
861861
862862
define void @goroutine_body2() {
863863
_llgo_0:
864-
%0 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
864+
%0 = call ptr asm sideeffect "mov $0, x26", "=r"()
865865
%1 = load { i64 }, ptr %0, align 4
866866
%2 = extractvalue { i64 } %1, 0
867867
ret void
@@ -891,7 +891,7 @@ _llgo_0:
891891
%2 = extractvalue { { ptr, ptr } } %1, 0
892892
%3 = extractvalue { ptr, ptr } %2, 1
893893
%4 = extractvalue { ptr, ptr } %2, 0
894-
call void asm sideeffect "movq $0, %mm0", "r,~{mm0},~{memory}"(ptr %3)
894+
call void asm sideeffect "mov x26, $0", "r,~{x26}"(ptr %3)
895895
call void %4()
896896
call void @free(ptr %0)
897897
ret ptr null
@@ -905,7 +905,7 @@ declare i32 @"github.com/goplus/llgo/runtime/internal/runtime.CreateThread"(ptr,
905905

906906
// TestNestedClosureIR verifies IR for closure with multi-field capture (nested scenario).
907907
func TestNestedClosureIR(t *testing.T) {
908-
prog := NewProgram(&Target{GOARCH: "amd64"})
908+
prog := NewProgram(&Target{GOARCH: "arm64"})
909909
prog.SetRuntime(func() *types.Package {
910910
fset := token.NewFileSet()
911911
imp := packages.NewImporter(fset)
@@ -935,7 +935,7 @@ source_filename = "test"
935935
936936
define i64 @nested_inner() {
937937
_llgo_0:
938-
%0 = call ptr asm sideeffect "movq %mm0, $0", "=r,~{memory}"()
938+
%0 = call ptr asm sideeffect "mov $0, x26", "=r"()
939939
%1 = load { i64, i64 }, ptr %0, align 4
940940
%2 = extractvalue { i64, i64 } %1, 0
941941
%3 = extractvalue { i64, i64 } %1, 1

ssa/target.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ type Target struct {
3939
// 3. Must be usable in LLVM inline asm constraints.
4040
//
4141
// Supported platforms:
42-
// - amd64: MM0 - MMX register (caller-saved), avoid MMX usage via -msse2
43-
// - 386: MM0 - MMX register (caller-saved), avoid MMX usage via -msse2
4442
// - arm64: X26 - callee-saved, reservable via +reserve-x26
4543
// - riscv64/riscv32: X27 (s11) - callee-saved register
4644
//

0 commit comments

Comments
 (0)