diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bed9b95..9294ab5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: runs-on: macos-latest strategy: matrix: - llvm: [14, 15, 16, 17, 18, 19, 20] + llvm: [14, 15, 16, 17, 18, 19, 20, 21, 22] steps: - name: Checkout uses: actions/checkout@v4 @@ -20,7 +20,6 @@ jobs: go-version: '1.22' # Optional step when a LLVM version is very new. - name: Update Homebrew - if: matrix.llvm == 20 run: brew update - name: Install LLVM run: HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} @@ -35,7 +34,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - llvm: [14, 15, 16, 17, 18, 19, 20] + llvm: [14, 15, 16, 17, 18, 19, 20, 21, 22] steps: - name: Checkout uses: actions/checkout@v4 @@ -56,3 +55,26 @@ jobs: if: matrix.llvm == 20 run: go test -v + test-linux-fedora: + # Fedora uses different paths than other systems, so testing it separately. + runs-on: ubuntu-24.04 + strategy: + matrix: + llvm: [19, 20, 21] + container: fedora:43 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install dependencies (default LLVM) + if: matrix.llvm == 21 + run: dnf install --assumeyes g++ golang llvm-devel + - name: Install dependencies (older LLVM) + if: matrix.llvm != 21 + run: dnf install --assumeyes g++ golang llvm${{ matrix.llvm }}-devel + - name: Test LLVM ${{ matrix.llvm }} + run: + go test -v -tags=llvm${{ matrix.llvm }} + - name: Test default LLVM + if: matrix.llvm == 20 + run: + go test -v diff --git a/captures_test.go b/captures_test.go new file mode 100644 index 0000000..6baaa96 --- /dev/null +++ b/captures_test.go @@ -0,0 +1,47 @@ +package llvm + +import ( + "strconv" + "strings" + "testing" +) + +// TestCapturesAttribute checks that the 'captures' parameter attribute +// (which replaced the boolean 'nocapture' enum attribute starting with +// LLVM 21) round-trips through the generic enum-attribute API, and that a +// value of 0 corresponds to CaptureInfo::none(), i.e. captures(none). +func TestCapturesAttribute(t *testing.T) { + majorVersion, _ := strconv.Atoi(strings.SplitN(Version, ".", 2)[0]) + if majorVersion < 21 { + t.Skip("not llvm 21") + } + + ctx := NewContext() + mod := ctx.NewModule("") + defer mod.Dispose() + + ptrType := PointerType(ctx.Int8Type(), 0) + ftyp := FunctionType(ctx.VoidType(), []Type{ptrType}, false) + fn := AddFunction(mod, "foo", ftyp) + + kind := AttributeKindID("captures") + if kind == 0 { + t.Fatal("captures kind id not found") + } + + attr := ctx.CreateEnumAttribute(kind, 0) + fn.AddAttributeAtIndex(1, attr) + + got := fn.GetEnumAttributeAtIndex(1, kind) + if got.IsNil() { + t.Fatal("expected captures attribute on param 1, got nil") + } + if val := got.GetEnumValue(); val != 0 { + t.Errorf("expected captures value 0 (none), got %d", val) + } + + text := mod.String() + if !strings.Contains(text, "captures(none)") { + t.Errorf("expected 'captures(none)' in output, got:\n%s", text) + } +} diff --git a/executionengine.go b/executionengine.go index 5fa8204..f9a3f99 100644 --- a/executionengine.go +++ b/executionengine.go @@ -18,8 +18,10 @@ package llvm #include */ import "C" -import "unsafe" -import "errors" +import ( + "errors" + "unsafe" +) func LinkInMCJIT() { C.LLVMLinkInMCJIT() } func LinkInInterpreter() { C.LLVMLinkInInterpreter() } @@ -110,6 +112,17 @@ func NewInterpreter(m Module) (ee ExecutionEngine, err error) { return } +func NewJITCompiler(m Module, optLevel int) (ee ExecutionEngine, err error) { + var cmsg *C.char + fail := C.LLVMCreateJITCompilerForModule(&ee.C, m.C, C.uint(optLevel), &cmsg) + if fail != 0 { + ee.C = nil + err = errors.New(C.GoString(cmsg)) + C.LLVMDisposeMessage(cmsg) + } + return +} + func NewMCJITCompilerOptions() MCJITCompilerOptions { var options C.struct_LLVMMCJITCompilerOptions C.LLVMInitializeMCJITCompilerOptions(&options, C.size_t(unsafe.Sizeof(C.struct_LLVMMCJITCompilerOptions{}))) @@ -159,6 +172,12 @@ func (ee ExecutionEngine) FindFunction(name string) (f Value) { return } +func (ee ExecutionEngine) GetFunctionAddress(name string) uint64 { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + return uint64(C.LLVMGetFunctionAddress(ee.C, cname)) +} + func (ee ExecutionEngine) RecompileAndRelinkFunction(f Value) unsafe.Pointer { return C.LLVMRecompileAndRelinkFunction(ee.C, f.C) } diff --git a/ir.go b/ir.go index 7e03ec6..47bf413 100644 --- a/ir.go +++ b/ir.go @@ -76,7 +76,6 @@ type ( ComdatSelectionKind C.LLVMComdatSelectionKind IntPredicate C.LLVMIntPredicate FloatPredicate C.LLVMRealPredicate - LandingPadClause C.LLVMLandingPadClauseTy InlineAsmDialect C.LLVMInlineAsmDialect ) @@ -344,15 +343,6 @@ const ( FloatPredicateTrue FloatPredicate = C.LLVMRealPredicateTrue ) -//------------------------------------------------------------------------- -// llvm.LandingPadClause -//------------------------------------------------------------------------- - -const ( - LandingPadCatch LandingPadClause = C.LLVMLandingPadCatch - LandingPadFilter LandingPadClause = C.LLVMLandingPadFilter -) - //------------------------------------------------------------------------- // llvm.InlineAsmDialect //------------------------------------------------------------------------- @@ -802,6 +792,18 @@ func (v Value) Operand(i int) (rv Value) { rv.C = C.LLVMGetOperand(v.C, C.unsi func (v Value) SetOperand(i int, op Value) { C.LLVMSetOperand(v.C, C.unsigned(i), op.C) } func (v Value) OperandsCount() int { return int(C.LLVMGetNumOperands(v.C)) } +// Operations on terminator instructions (br, switch, etc). Unlike operands, +// the number and meaning of successors has been stable across LLVM versions, +// making these a safe, version-independent way to enumerate the destination +// blocks of a switch instruction: successor 0 is the default destination, +// and successors 1..N-1 correspond to case 0..N-2 (see GetSwitchCaseValue for +// the matching case value). +func (v Value) SuccessorsCount() int { return int(C.LLVMGetNumSuccessors(v.C)) } +func (v Value) Successor(i int) (bb BasicBlock) { + bb.C = C.LLVMGetSuccessor(v.C, C.unsigned(i)) + return +} + // Operations on constants of any type func ConstNull(t Type) (v Value) { v.C = C.LLVMConstNull(t.C); return } func ConstAllOnes(t Type) (v Value) { v.C = C.LLVMConstAllOnes(t.C); return } @@ -928,9 +930,6 @@ func ConstNUWAdd(lhs, rhs Value) (v Value) { v.C = C.LLVMConstNUWAdd(lhs.C, rhs. func ConstSub(lhs, rhs Value) (v Value) { v.C = C.LLVMConstSub(lhs.C, rhs.C); return } func ConstNSWSub(lhs, rhs Value) (v Value) { v.C = C.LLVMConstNSWSub(lhs.C, rhs.C); return } func ConstNUWSub(lhs, rhs Value) (v Value) { v.C = C.LLVMConstNUWSub(lhs.C, rhs.C); return } -func ConstMul(lhs, rhs Value) (v Value) { v.C = C.LLVMConstMul(lhs.C, rhs.C); return } -func ConstNSWMul(lhs, rhs Value) (v Value) { v.C = C.LLVMConstNSWMul(lhs.C, rhs.C); return } -func ConstNUWMul(lhs, rhs Value) (v Value) { v.C = C.LLVMConstNUWMul(lhs.C, rhs.C); return } func ConstXor(lhs, rhs Value) (v Value) { v.C = C.LLVMConstXor(lhs.C, rhs.C); return } func ConstGEP(t Type, v Value, indices []Value) (rv Value) { diff --git a/ir_test.go b/ir_test.go index 57b306f..a912aec 100644 --- a/ir_test.go +++ b/ir_test.go @@ -62,7 +62,6 @@ func TestAttributes(t *testing.T) { "nest", "noalias", "nobuiltin", - "nocapture", "noduplicate", "noimplicitfloat", "noinline", diff --git a/llvm_config_darwin_llvm14.go b/llvm_config_darwin_llvm14.go deleted file mode 100644 index 2a3c8a9..0000000 --- a/llvm_config_darwin_llvm14.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && llvm14 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@14/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++14 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@14/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@14/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++14 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@14/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_darwin_llvm15.go b/llvm_config_darwin_llvm15.go deleted file mode 100644 index 07a72fc..0000000 --- a/llvm_config_darwin_llvm15.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && llvm15 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@15/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++14 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@15/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++14 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_darwin_llvm16.go b/llvm_config_darwin_llvm16.go deleted file mode 100644 index 2acf0b0..0000000 --- a/llvm_config_darwin_llvm16.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && llvm16 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@16/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++17 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@16/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++17 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_darwin_llvm17.go b/llvm_config_darwin_llvm17.go deleted file mode 100644 index 3dc8f26..0000000 --- a/llvm_config_darwin_llvm17.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && llvm17 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@17/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++17 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@17/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@17/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++17 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@17/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_darwin_llvm18.go b/llvm_config_darwin_llvm18.go deleted file mode 100644 index 744a11e..0000000 --- a/llvm_config_darwin_llvm18.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && llvm18 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++17 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++17 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_darwin_llvm19.go b/llvm_config_darwin_llvm19.go deleted file mode 100644 index eae7744..0000000 --- a/llvm_config_darwin_llvm19.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && llvm19 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@19/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++17 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@19/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@19/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++17 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@19/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_darwin_llvm20.go b/llvm_config_darwin_llvm20.go deleted file mode 100644 index 22d2826..0000000 --- a/llvm_config_darwin_llvm20.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !byollvm && darwin && !llvm14 && !llvm15 && !llvm16 && !llvm17 && !llvm18 && !llvm19 - -package llvm - -// Automatically generated by `make config BUILDDIR=`, do not edit. - -// #cgo amd64 CPPFLAGS: -I/usr/local/opt/llvm@20/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo amd64 CXXFLAGS: -std=c++17 -// #cgo amd64 LDFLAGS: -L/usr/local/opt/llvm@20/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -// #cgo arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@20/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo arm64 CXXFLAGS: -std=c++17 -// #cgo arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@20/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm14.go b/llvm_config_linux_llvm14.go deleted file mode 100644 index 3f91a53..0000000 --- a/llvm_config_linux_llvm14.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && llvm14 - -package llvm - -// #cgo CPPFLAGS: -I/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++14 -// #cgo LDFLAGS: -L/usr/lib/llvm-14/lib -lLLVM-14 -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm15.go b/llvm_config_linux_llvm15.go deleted file mode 100644 index 607ed7e..0000000 --- a/llvm_config_linux_llvm15.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && llvm15 - -package llvm - -// #cgo CPPFLAGS: -I/usr/lib/llvm-15/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++14 -// #cgo LDFLAGS: -L/usr/lib/llvm-15/lib -lLLVM-15 -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm16.go b/llvm_config_linux_llvm16.go deleted file mode 100644 index 4208cf4..0000000 --- a/llvm_config_linux_llvm16.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && llvm16 - -package llvm - -// #cgo CPPFLAGS: -I/usr/lib/llvm-16/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++17 -// #cgo LDFLAGS: -L/usr/lib/llvm-16/lib -lLLVM-16 -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm17.go b/llvm_config_linux_llvm17.go deleted file mode 100644 index f2951d7..0000000 --- a/llvm_config_linux_llvm17.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && llvm17 - -package llvm - -// #cgo CPPFLAGS: -I/usr/include/llvm-17 -I/usr/include/llvm-c-17 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++17 -// #cgo LDFLAGS: -L/usr/lib/llvm-17/lib -lLLVM-17 -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm18.go b/llvm_config_linux_llvm18.go deleted file mode 100644 index a4bbea0..0000000 --- a/llvm_config_linux_llvm18.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && llvm18 - -package llvm - -// #cgo CPPFLAGS: -I/usr/include/llvm-18 -I/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++17 -// #cgo LDFLAGS: -L/usr/lib/llvm-18/lib -lLLVM-18 -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm19.go b/llvm_config_linux_llvm19.go deleted file mode 100644 index ec7c36a..0000000 --- a/llvm_config_linux_llvm19.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && llvm19 - -package llvm - -// #cgo CPPFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++17 -// #cgo LDFLAGS: -L/usr/lib/llvm-19/lib -lLLVM-19 -import "C" - -type run_build_sh int diff --git a/llvm_config_linux_llvm20.go b/llvm_config_linux_llvm20.go deleted file mode 100644 index a610933..0000000 --- a/llvm_config_linux_llvm20.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && linux && !llvm14 && !llvm15 && !llvm16 && !llvm17 && !llvm18 && !llvm19 - -package llvm - -// #cgo CPPFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++17 -// #cgo LDFLAGS: -L/usr/lib/llvm-20/lib -lLLVM-20 -import "C" - -type run_build_sh int diff --git a/llvm_config_llvm14.go b/llvm_config_llvm14.go new file mode 100644 index 0000000..9d38a5b --- /dev/null +++ b/llvm_config_llvm14.go @@ -0,0 +1,16 @@ +//go:build !byollvm && llvm14 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@14/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++14 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@14/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@14/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++14 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@14/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo linux CPPFLAGS: -I/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++14 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-14/lib -lLLVM-14 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm15.go b/llvm_config_llvm15.go new file mode 100644 index 0000000..34aebc0 --- /dev/null +++ b/llvm_config_llvm15.go @@ -0,0 +1,16 @@ +//go:build !byollvm && llvm15 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@15/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++14 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@15/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++14 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo linux CPPFLAGS: -I/usr/lib/llvm-15/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++14 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lLLVM-15 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm16.go b/llvm_config_llvm16.go new file mode 100644 index 0000000..936ca0f --- /dev/null +++ b/llvm_config_llvm16.go @@ -0,0 +1,16 @@ +//go:build !byollvm && llvm16 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@16/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@16/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo linux CPPFLAGS: -I/usr/lib/llvm-16/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lLLVM-16 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm17.go b/llvm_config_llvm17.go new file mode 100644 index 0000000..6a00b39 --- /dev/null +++ b/llvm_config_llvm17.go @@ -0,0 +1,16 @@ +//go:build !byollvm && llvm17 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@17/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@17/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@17/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@17/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo linux CPPFLAGS: -I/usr/include/llvm-17 -I/usr/include/llvm-c-17 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-17/lib -lLLVM-17 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm18.go b/llvm_config_llvm18.go new file mode 100644 index 0000000..c41fea0 --- /dev/null +++ b/llvm_config_llvm18.go @@ -0,0 +1,16 @@ +//go:build !byollvm && llvm18 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo linux CPPFLAGS: -I/usr/include/llvm-18 -I/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-18/lib -lLLVM-18 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm19.go b/llvm_config_llvm19.go new file mode 100644 index 0000000..f5493ef --- /dev/null +++ b/llvm_config_llvm19.go @@ -0,0 +1,19 @@ +//go:build !byollvm && llvm19 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@19/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@19/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@19/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@19/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo freebsd CPPFLAGS: -I/usr/local/llvm19/include -I/usr/local/llvm19/include/llvm-c -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo freebsd CXXFLAGS: -std=c++17 +// #cgo freebsd LDFLAGS: -L/usr/local/llvm19/lib -lLLVM +// #cgo linux CPPFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib64/llvm19/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-19/lib -L/usr/lib64/llvm19/lib -lLLVM-19 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm20.go b/llvm_config_llvm20.go new file mode 100644 index 0000000..2132c5a --- /dev/null +++ b/llvm_config_llvm20.go @@ -0,0 +1,19 @@ +//go:build !byollvm && !llvm14 && !llvm15 && !llvm16 && !llvm17 && !llvm18 && !llvm19 && !llvm21 && !llvm22 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@20/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@20/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@20/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@20/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo freebsd CPPFLAGS: -I/usr/local/llvm20/include -I/usr/local/llvm20/include/llvm-c -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo freebsd CXXFLAGS: -std=c++17 +// #cgo freebsd LDFLAGS: -L/usr/local/llvm20/lib -lLLVM +// #cgo linux CPPFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib64/llvm20/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-20/lib -L/usr/lib64/llvm20/lib64 -lLLVM-20 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm21.go b/llvm_config_llvm21.go new file mode 100644 index 0000000..263c2fc --- /dev/null +++ b/llvm_config_llvm21.go @@ -0,0 +1,19 @@ +//go:build !byollvm && llvm21 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@21/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@21/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@21/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@21/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo freebsd CPPFLAGS: -I/usr/local/llvm21/include -I/usr/local/llvm21/include/llvm-c -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo freebsd CXXFLAGS: -std=c++17 +// #cgo freebsd LDFLAGS: -L/usr/local/llvm21/lib -lLLVM +// #cgo linux CPPFLAGS: -I/usr/include/llvm-21 -I/usr/include/llvm-c-21 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-21/lib -lLLVM-21 +import "C" + +type run_build_sh int diff --git a/llvm_config_llvm22.go b/llvm_config_llvm22.go new file mode 100644 index 0000000..103e930 --- /dev/null +++ b/llvm_config_llvm22.go @@ -0,0 +1,19 @@ +//go:build !byollvm && llvm22 + +package llvm + +// #cgo darwin,amd64 CPPFLAGS: -I/usr/local/opt/llvm@22/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,amd64 CXXFLAGS: -std=c++17 +// #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@22/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo darwin,arm64 CPPFLAGS: -I/opt/homebrew/opt/llvm@22/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo darwin,arm64 CXXFLAGS: -std=c++17 +// #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@22/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM -lz -lm +// #cgo freebsd CPPFLAGS: -I/usr/local/llvm22/include -I/usr/local/llvm22/include/llvm-c -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo freebsd CXXFLAGS: -std=c++17 +// #cgo freebsd LDFLAGS: -L/usr/local/llvm22/lib -lLLVM +// #cgo linux CPPFLAGS: -I/usr/include/llvm-22 -I/usr/include/llvm-c-22 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS +// #cgo linux CXXFLAGS: -std=c++17 +// #cgo linux LDFLAGS: -L/usr/lib/llvm-22/lib -lLLVM-22 +import "C" + +type run_build_sh int diff --git a/switch_llvm22.go b/switch_llvm22.go new file mode 100644 index 0000000..0c70b08 --- /dev/null +++ b/switch_llvm22.go @@ -0,0 +1,21 @@ +//go:build llvm22 + +package llvm + +/* +#include "llvm-c/Core.h" +*/ +import "C" + +// GetSwitchCaseValue obtains the case value for a successor of a switch +// instruction. i corresponds to the successor index; the first successor (0) +// is the default destination, so i must be greater than zero. +// +// LLVM 22 stopped exposing switch case values as regular instruction +// operands (only the condition and destination-block operands remain), so +// this is implemented via the new LLVMGetSwitchCaseValue C API added in the +// same release. +func (v Value) GetSwitchCaseValue(i int) (rv Value) { + rv.C = C.LLVMGetSwitchCaseValue(v.C, C.unsigned(i)) + return +} diff --git a/switch_pre22.go b/switch_pre22.go new file mode 100644 index 0000000..cfa381c --- /dev/null +++ b/switch_pre22.go @@ -0,0 +1,15 @@ +//go:build !llvm22 + +package llvm + +// GetSwitchCaseValue obtains the case value for a successor of a switch +// instruction. i corresponds to the successor index; the first successor (0) +// is the default destination, so i must be greater than zero. +// +// Before LLVM 22, switch case values were stored as regular instruction +// operands (alternating with their destination blocks, after the leading +// condition/default-destination pair), so this is implemented via Operand +// access instead of the LLVM 22+-only LLVMGetSwitchCaseValue. +func (v Value) GetSwitchCaseValue(i int) Value { + return v.Operand(2 * i) +} diff --git a/switch_test.go b/switch_test.go new file mode 100644 index 0000000..aa7ca26 --- /dev/null +++ b/switch_test.go @@ -0,0 +1,76 @@ +package llvm + +import ( + "os" + "testing" +) + +// TestSwitchCaseValue checks that GetSwitchCaseValue/SuccessorsCount/Successor +// correctly read a switch instruction's cases across LLVM versions. LLVM 22 +// stopped exposing case values as regular instruction operands (only the +// condition and destination-block operands remain), instead requiring the +// new LLVMGetSwitchCaseValue API; code that assumed the old operand layout +// silently reads a destination block where it expects a case value. +func TestSwitchCaseValue(t *testing.T) { + src := ` +define void @foo(i64 %callback) { +entry: + switch i64 %callback, label %default [ + i64 0, label %case0 + i64 5, label %case1 + ] +default: + ret void +case0: + ret void +case1: + ret void +} +` + f, err := os.CreateTemp("", "switchcase-*.ll") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + if _, err := f.WriteString(src); err != nil { + t.Fatal(err) + } + f.Close() + + ctx := NewContext() + defer ctx.Dispose() + + buf, err := NewMemoryBufferFromFile(f.Name()) + if err != nil { + t.Fatal(err) + } + + m, err := ctx.ParseIR(buf) + if err != nil { + t.Fatal(err) + } + defer m.Dispose() + + fn := m.NamedFunction("foo") + sw := fn.EntryBasicBlock().FirstInstruction() + + if n := sw.SuccessorsCount(); n != 3 { + t.Fatalf("expected 3 successors (default + 2 cases), got %d", n) + } + if got := sw.Successor(0).AsValue().Name(); got != "default" { + t.Errorf("expected default destination %q, got %q", "default", got) + } + + wantCaseValues := []uint64{0, 5} + wantCaseDests := []string{"case0", "case1"} + for i, want := range wantCaseValues { + successor := i + 1 + val := sw.GetSwitchCaseValue(successor) + if got := val.ZExtValue(); got != want { + t.Errorf("case %d: expected value %d, got %d", i, want, got) + } + if got := sw.Successor(successor).AsValue().Name(); got != wantCaseDests[i] { + t.Errorf("case %d: expected destination %q, got %q", i, wantCaseDests[i], got) + } + } +}