Skip to content

ir: bind constant-range attribute creation - #52

Merged
xushiwei merged 1 commit into
xgo-dev:xgofrom
zhouguangyuan0718:codex/constant-range-attribute-20260906
Sep 7, 2026
Merged

ir: bind constant-range attribute creation#52
xushiwei merged 1 commit into
xgo-dev:xgofrom
zhouguangyuan0718:codex/constant-range-attribute-20260906

Conversation

@zhouguangyuan0718

Copy link
Copy Markdown

Clients cannot currently construct LLVM constant-range attributes through the Go API. For example, declaring a nonnegative i32 or i64 return range requires a private cgo bridge in the client.

Add Context.CreateConstantRangeAttribute(kind, numBits, lowerWords, upperWords) around LLVMCreateConstantRangeAttribute. The bounds use least-significant-word-first uint64 slices, support multiple words, and are checked for invalid widths and incorrect word counts before entering C. The context owns the resulting attribute; input slices can be reused immediately.

A version-guarded forwarding function preserves compilation against LLVM 14–18, returning a nil attribute where the API is unavailable. LLVM 19 and later use the upstream LLVM-C constructor.

Tests cover 1/32/64/65/128-bit ranges, multiword ordering, return-attribute round-trips, LLVM verification, independence from input slice storage, and malformed bounds. The existing CI matrix also exercises the pre-19 fallback.

Validation on macOS arm64:

  • Full binding suite with LLVM 22.1.8: go test -tags=byollvm ./... -count=1.
  • Full binding suite with LLVM 19.1.7: go test -tags=byollvm,llvm19 ./... -count=1.

Consumer: xgo-dev/llgo#2510 will use this API and remove its private cgo bridge.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: CreateConstantRangeAttribute Go binding

A clean, well-constructed addition. The LLVMGo* C shim guarding on LLVM_VERSION_MAJOR >= 19 matches the existing binding style, the word-count/width validation is sound, and the cgo pointer pass-through is safe: the upstream LLVMCreateConstantRangeAttribute copies the words into an APInt and does not retain the Go slice storage.

Verified clean:

  • Memory safety&lowerWords[0]/&upperWords[0] are only reached after numBits > 0 (so nwords >= 1) and the exact-length check, so no empty-slice deref; C reads exactly ceil(numBits/64) words, matching the Go count. Overflow guard on numBits prevents C.unsigned truncation.
  • Performance — no allocations or per-word marshalling; single cgo call.
  • Docs — the word order (least-significant-word-first), ceil(numBits/64) requirement, panic conditions, and pre-19 nil behavior all match the implementation and are confirmed by the tests (e.g. the 128-bit case 3 + 2*2^64 = 36893488147419103235).
  • TestsTestConstantRangeAttribute even zeroes the input slices after construction to confirm LLVM copied the words; invalid-bounds cases cover the panic paths.

Two minor, non-blocking suggestions inline. No blocking issues found.

Comment thread ir.go
if len(lowerWords) != nwords || len(upperWords) != nwords {
panic("llvm: constant range bounds have incorrect word counts")
}
a.C = C.LLVMGoCreateConstantRangeAttribute(c.C, C.unsigned(kind), C.unsigned(numBits),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Note the nwords>=1 invariant that keeps &lowerWords[0] safe

The &lowerWords[0] / &upperWords[0] dereference is safe today only because numBits > 0 forces nwords >= 1 and the preceding length check guarantees both slices are non-empty. This is a fragile coupling: any future loosening of the validation could silently introduce an out-of-bounds [0] access across the cgo boundary. A one-line comment noting that nwords >= 1 is guaranteed above would protect the invariant. Non-blocking.

Comment thread ir.go
// CreateConstantRangeAttribute creates a constant-range attribute such as
// "range". Bounds are unsigned words in least-significant-word-first order;
// each slice must contain exactly ceil(numBits/64) words and numBits must be
// positive. Invalid widths or word counts panic. On LLVM before 19, which does

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Doc says pre-19 returns nil, but validation runs on all versions first

The comment states "On LLVM before 19 ... it returns a nil Attribute," but the width/word-count validation (which can panic) runs unconditionally before the version-gated C call. So on a pre-19 build an invalid-argument call panics rather than returning nil. The behavior is arguably better, but the doc reads as a pure "always nil" path. Consider clarifying, e.g. "a nil Attribute is returned for otherwise-valid arguments." Non-blocking.

@xushiwei
xushiwei merged commit 36244bb into xgo-dev:xgo Sep 7, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants