Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/actions/setup-windows-llvm19/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Setup Windows LLVM 19
description: Install the pinned LLVM 19 toolchain used by the Windows CI lanes.

runs:
using: composite
steps:
- name: Set up MSYS2 for LLVM 19
uses: msys2/setup-msys2@v2
with:
msystem: CLANG64
path-type: inherit
update: true

- name: Install LLVM 19
shell: msys2 {0}
env:
LLVM_VERSION: '19.1.7'
LLVM_PACKAGE_VERSION: '19.1.7-1'
run: |
set -euo pipefail
repo=https://repo.msys2.org/mingw/clang64
prefix=mingw-w64-clang-x86_64
# MSYS2 is rolling and no longer publishes LLVM 19 in its current
# repository metadata. Install one archived, version-consistent set
# so Windows exercises the same LLVM major as Linux and macOS.
packages=(
"clang-$LLVM_PACKAGE_VERSION"
"clang-libs-$LLVM_PACKAGE_VERSION"
"compiler-rt-$LLVM_PACKAGE_VERSION"
"llvm-$LLVM_PACKAGE_VERSION"
"llvm-libs-$LLVM_PACKAGE_VERSION"
"lld-$LLVM_PACKAGE_VERSION"
"libc++-$LLVM_PACKAGE_VERSION"
"libunwind-$LLVM_PACKAGE_VERSION"
"gettext-runtime-0.22.5-2"
"libffi-3.4.6-1"
"libiconv-1.17-4"
"libxml2-2.12.9-2"
"xz-5.6.3-3"
"zlib-1.3.1-1"
"zstd-1.5.6-2"
)
urls=()
for package in "${packages[@]}"; do
urls+=("$repo/$prefix-$package-any.pkg.tar.zst")
done

# These archived packages predate the gcc-libs -> cc-libs virtual
# dependency rename. libc++ 19 supplies the runtime; acknowledge only
# that metadata rename rather than disabling dependency checks.
pacman --noconfirm -U \
--assume-installed "$prefix-cc-libs=$LLVM_VERSION" \
"${urls[@]}"

if [[ "$(llvm-config --version)" != "$LLVM_VERSION" ]]; then
echo "expected LLVM $LLVM_VERSION, got $(llvm-config --version)" >&2
exit 1
fi

flatten() {
local value=$1
value="${value//$'\r'/}"
value="${value//$'\n'/ }"
printf '%s' "$value"
}
echo "CGO_CFLAGS=$(flatten "$(llvm-config --cflags)")" >> "$GITHUB_ENV"
echo "CGO_CXXFLAGS=$(flatten "$(llvm-config --cxxflags)")" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=$(flatten "$(llvm-config --ldflags --libs all --system-libs)")" >> "$GITHUB_ENV"
clang_bin="$(cygpath -w /clang64/bin)"
echo "CC=$clang_bin\\clang.exe" >> "$GITHUB_ENV"
echo "CXX=$clang_bin\\clang++.exe" >> "$GITHUB_ENV"
echo 'CGO_ENABLED=1' >> "$GITHUB_ENV"
echo 'GOFLAGS=-tags=byollvm' >> "$GITHUB_ENV"
echo "$clang_bin" >> "$GITHUB_PATH"
89 changes: 77 additions & 12 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version: '1.26.x'
cache: true

- name: Go fmt check
Expand Down Expand Up @@ -72,12 +72,14 @@ jobs:
os:
- ubuntu-latest
- macos-latest
- windows-latest
go-version:
- '1.21.x'
- '1.22.x'
- '1.23.x'
- '1.24.x'
- '1.25.x'
- '1.26.x'

steps:
- name: Checkout
Expand All @@ -98,23 +100,40 @@ jobs:
brew install llvm@19
echo "PATH=$(brew --prefix llvm@19)/bin:$PATH" >> $GITHUB_ENV

- name: Setup Python (Windows)
if: runner.os == 'Windows'
uses: actions/setup-python@v6
with:
python-version: '3.x'

- name: Install LLVM 19 (Windows)
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-llvm19

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true

- name: Stdlib asm corpus gate
shell: bash
run: |
chmod +x scripts/check-stdlib-corpus.sh
scripts/check-stdlib-corpus.sh

test:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
runs-on: ${{ matrix.os }}
strategy:
# Keep both matrix variants visible even if one fails.
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
go-version:
- '1.21.x'
- '1.22.x'
Expand All @@ -133,32 +152,77 @@ jobs:
go-version: ${{ matrix.go-version }}
cache: true

- name: Install LLVM 19
- name: Setup Python (Windows)
if: runner.os == 'Windows'
uses: actions/setup-python@v6
with:
python-version: '3.x'

- name: Install LLVM 19 (Ubuntu)
if: runner.os == 'Linux'
run: |
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-19 main" | sudo tee /etc/apt/sources.list.d/llvm.list
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/llvm-snapshot.asc >/dev/null
sudo apt-get update
sudo apt-get install -y llvm-19-dev clang-19 libclang-19-dev lld-19 libunwind-19-dev libc++-19-dev
echo "PATH=/usr/lib/llvm-19/bin:$PATH" >> $GITHUB_ENV

- name: Install LLVM 19 (Windows)
if: runner.os == 'Windows'
uses: ./.github/actions/setup-windows-llvm19

- name: LLVM tools info
shell: bash
run: |
which llc
command -v llc
llc --version
which clang
command -v clang
clang --version

- name: Go test
- name: Go test (Ubuntu)
if: runner.os != 'Windows'
run: go test ./...

- name: Go test (cmd/plan9asm)
- name: Go test (cmd/plan9asm, Ubuntu)
if: runner.os != 'Windows'
run: go test ./...
working-directory: cmd/plan9asm

- name: Go test (cmd/plan9asmll)
- name: Go test (cmd/plan9asmll, Ubuntu)
if: runner.os != 'Windows'
run: go test ./...
working-directory: cmd/plan9asmll

- name: Go test with coverage (Windows)
if: runner.os == 'Windows' && matrix.go-version == '1.26.x'
shell: bash
run: |
set -euo pipefail
go test ./... -coverprofile=coverage-windows-root.out
(cd cmd/plan9asm && go test ./... -coverprofile=../../coverage-windows-plan9asm.out)
(cd cmd/plan9asmll && go test ./... -coverprofile=../../coverage-windows-plan9asmll.out)

- name: Go test (Windows)
if: runner.os == 'Windows' && matrix.go-version != '1.26.x'
shell: bash
run: |
set -euo pipefail
go test ./...
(cd cmd/plan9asm && go test ./...)
(cd cmd/plan9asmll && go test ./...)

- name: Upload Windows coverage to Codecov
if: runner.os == 'Windows' && matrix.go-version == '1.26.x'
uses: codecov/codecov-action@v5
with:
use_oidc: true
files: ./coverage-windows-root.out,./coverage-windows-plan9asm.out,./coverage-windows-plan9asmll.out
disable_search: true
flags: windows
name: windows-go1.26
fail_ci_if_error: true
verbose: true

arm-scan:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -192,7 +256,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.26.1'
go-version: '1.26.x'
cache: true

- name: ARM scan gate
Expand Down Expand Up @@ -229,7 +293,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
go-version: '1.26.x'
cache: true

- name: Install LLVM 19
Expand All @@ -256,7 +320,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.25.x'
go-version: '1.26.x'
cache: true

- name: Install LLVM 19
Expand Down Expand Up @@ -289,7 +353,8 @@ jobs:
with:
use_oidc: true
files: ./coverage-root.out
disable_search: true
flags: unittests
name: ubuntu-go1.25
name: ubuntu-go1.26
fail_ci_if_error: false
verbose: true
32 changes: 32 additions & 0 deletions amd64_ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,13 @@ func parseSBRef(sym string) (base string, off int64, ok bool) {
}

func (c *amd64Ctx) addrFromMem(mem MemRef) (addrI64 string, err error) {
if mem.Segment != "" {
return "", fmt.Errorf("segment-relative memory requires a segment-aware pointer")
}
return c.addrFromPlainMem(mem)
}

func (c *amd64Ctx) addrFromPlainMem(mem MemRef) (addrI64 string, err error) {
base, err := c.loadReg(mem.Base)
if err != nil {
return "", err
Expand Down Expand Up @@ -1187,6 +1194,31 @@ func (c *amd64Ctx) addrFromMem(mem MemRef) (addrI64 string, err error) {
return cur, nil
}

func (c *amd64Ctx) ptrFromMem(mem MemRef) (ptr, ptrType string, err error) {
addr, err := c.addrFromPlainMem(mem)
if err != nil {
return "", "", err
}
if mem.Segment == "" {
return c.ptrFromAddrI64(addr), "ptr", nil
}
addressSpace := 0
switch mem.Segment {
case GS:
// LLVM's x86 target maps address space 256 to the GS segment.
addressSpace = 256
case FS:
// LLVM's x86 target maps address space 257 to the FS segment.
addressSpace = 257
default:
return "", "", fmt.Errorf("unsupported x86 segment register %s", mem.Segment)
}
t := c.newTmp()
ptrType = fmt.Sprintf("ptr addrspace(%d)", addressSpace)
fmt.Fprintf(c.b, " %%%s = inttoptr i64 %s to %s\n", t, addr, ptrType)
return "%" + t, ptrType, nil
}

func (c *amd64Ctx) ptrFromAddrI64(addrI64 string) string {
t := c.newTmp()
fmt.Fprintf(c.b, " %%%s = inttoptr i64 %s to ptr\n", t, addrI64)
Expand Down
19 changes: 15 additions & 4 deletions amd64_lower_mov.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,19 @@ func (c *amd64Ctx) lowerMov(op Op, ins Instr) (ok bool, terminated bool, err err
// MOVQ src, dst
switch dst.Kind {
case OpReg:
v, err := c.evalI64(src)
var v string
var err error
if src.Kind == OpMem && src.Mem.Segment != "" {
p, ptrType, err2 := c.ptrFromMem(src.Mem)
if err2 != nil {
return true, false, err2
}
t := c.newTmp()
fmt.Fprintf(c.b, " %%%s = load i64, %s %s, align 1\n", t, ptrType, p)
v = "%" + t
} else {
v, err = c.evalI64(src)
}
if err != nil {
// Allow MOVQ mem, reg.
if src.Kind == OpMem {
Expand Down Expand Up @@ -239,12 +251,11 @@ func (c *amd64Ctx) lowerMov(op Op, ins Instr) (ok bool, terminated bool, err err
if err != nil {
return true, false, err
}
addr, err := c.addrFromMem(dst.Mem)
p, ptrType, err := c.ptrFromMem(dst.Mem)
if err != nil {
return true, false, err
}
p := c.ptrFromAddrI64(addr)
fmt.Fprintf(c.b, " store i64 %s, ptr %s, align 1\n", v, p)
fmt.Fprintf(c.b, " store i64 %s, %s %s, align 1\n", v, ptrType, p)
return true, false, nil
case OpSym:
if !strings.HasSuffix(strings.TrimSpace(dst.Sym), "(SB)") {
Expand Down
6 changes: 5 additions & 1 deletion amd64_needed.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func funcNeedsAMD64CFG(fn Func) bool {
}
// Keep the linear path only for the tiny subset it currently lowers.
switch Op(op) {
case OpTEXT, OpRET, OpBYTE, OpMOVQ, OpMOVL, OpADDQ, OpSUBQ, OpXORQ, OpCPUID, OpXGETBV:
case OpTEXT, OpBYTE, OpMOVQ, OpMOVL, OpADDQ, OpSUBQ, OpXORQ, OpCPUID, OpXGETBV:
// For MOVQ/MOVL, linear lowering supports immediate/reg/FP value flow.
// Addressing forms (mem/sym) require CFG lowering.
if (op == "MOVQ" || op == "MOVL") && len(ins.Args) == 2 {
Expand All @@ -36,6 +36,10 @@ func funcNeedsAMD64CFG(fn Func) bool {
}
}
}
case OpRET:
if len(ins.Args) != 0 {
return true
}
default:
return true
}
Expand Down
Loading
Loading