-
Notifications
You must be signed in to change notification settings - Fork 7
llvm: bind LLVM 22 pointer address extraction #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #include "PtrToAddrBindings.h" | ||
| #include "llvm/Config/llvm-config.h" | ||
|
|
||
| #if LLVM_VERSION_MAJOR >= 22 | ||
| #include "llvm/IR/Constants.h" | ||
| #include "llvm/IR/IRBuilder.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| LLVMValueRef LLVMGoBuildPtrToAddr(LLVMBuilderRef B, LLVMValueRef V, | ||
| const char *Name) { | ||
| return wrap(unwrap(B)->CreatePtrToAddr(unwrap(V), Name)); | ||
| } | ||
|
|
||
| LLVMValueRef LLVMGoConstPtrToAddr(LLVMValueRef V, LLVMTypeRef T) { | ||
| return wrap(ConstantExpr::getPtrToAddr(unwrap<Constant>(V), unwrap(T))); | ||
| } | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #ifndef LLVM_BINDINGS_GO_PTRTOADDR_H | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Missing LLVM license header in new C++ files Every existing binding file ( |
||
| #define LLVM_BINDINGS_GO_PTRTOADDR_H | ||
|
|
||
| #include "llvm-c/Core.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| LLVMValueRef LLVMGoBuildPtrToAddr(LLVMBuilderRef B, LLVMValueRef V, | ||
| const char *Name); | ||
| LLVMValueRef LLVMGoConstPtrToAddr(LLVMValueRef V, LLVMTypeRef T); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| //go:build llvm22 || (!llvm14 && !llvm15 && !llvm16 && !llvm17 && !llvm18 && !llvm19 && !llvm20 && !llvm21) | ||
|
|
||
| package llvm | ||
|
|
||
| /* | ||
| #include "PtrToAddrBindings.h" | ||
| #include <stdlib.h> | ||
| */ | ||
| import "C" | ||
| import "unsafe" | ||
|
|
||
| const PtrToAddr Opcode = C.LLVMPtrToAddr | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P3] PtrToAddr Opcode const lives apart from the others in ir.go All other |
||
|
|
||
| // CreatePtrToAddr extracts the address of val without capturing its provenance. | ||
| // The result uses the pointer address space's index width from the containing | ||
| // module's DataLayout (and preserves the shape of pointer vectors). The builder | ||
| // must have an insertion point in a module with the intended DataLayout. | ||
| // Available with LLVM 22 and later. | ||
| func (b Builder) CreatePtrToAddr(val Value, name string) (v Value) { | ||
| cname := C.CString(name) | ||
| defer C.free(unsafe.Pointer(cname)) | ||
| v.C = C.LLVMGoBuildPtrToAddr(b.C, val.C, cname) | ||
| return | ||
| } | ||
|
|
||
| // ConstPtrToAddr extracts a constant pointer's address without capturing its | ||
| // provenance. t must have the pointer address space's DataLayout index width | ||
| // and the same scalar or vector shape as val. Available with LLVM 22 and later. | ||
| func ConstPtrToAddr(val Value, t Type) (v Value) { | ||
| v.C = C.LLVMGoConstPtrToAddr(val.C, t.C) | ||
| return | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| //go:build llvm22 || (!llvm14 && !llvm15 && !llvm16 && !llvm17 && !llvm18 && !llvm19 && !llvm20 && !llvm21) | ||
|
|
||
| package llvm | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestPtrToAddrDataLayoutAndRoundTrip(t *testing.T) { | ||
| ctx := NewContext() | ||
| defer ctx.Dispose() | ||
| mod := ctx.NewModule("ptrtoaddr") | ||
| defer mod.Dispose() | ||
| mod.SetDataLayout("e-p:64:64-p1:64:64:64:32") | ||
| builder := ctx.NewBuilder() | ||
| defer builder.Dispose() | ||
|
|
||
| for _, tc := range []struct { | ||
| name string | ||
| ptr Type | ||
| addr Type | ||
| }{ | ||
| {"scalar", PointerType(ctx.Int8Type(), 0), ctx.Int64Type()}, | ||
| {"narrow_index", PointerType(ctx.Int8Type(), 1), ctx.Int32Type()}, | ||
| {"vector", VectorType(PointerType(ctx.Int8Type(), 1), 2), VectorType(ctx.Int32Type(), 2)}, | ||
| } { | ||
| fn := AddFunction(mod, tc.name, FunctionType(tc.addr, []Type{tc.ptr}, false)) | ||
| builder.SetInsertPointAtEnd(ctx.AddBasicBlock(fn, "entry")) | ||
| addr := builder.CreatePtrToAddr(fn.Param(0), "addr") | ||
| if addr.Type() != tc.addr || addr.InstructionOpcode() != PtrToAddr { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P3] Combined assertion shares one error message This check tests two distinct properties (result type and opcode) but reports a single |
||
| t.Fatalf("%s: unexpected ptrtoaddr: %s", tc.name, addr.String()) | ||
| } | ||
| builder.CreateRet(addr) | ||
| } | ||
|
|
||
| global := AddGlobal(mod, ctx.Int8Type(), "data") | ||
| addr := ConstPtrToAddr(global, ctx.Int64Type()) | ||
| if addr.Opcode() != PtrToAddr { | ||
| t.Fatalf("unexpected constant opcode: %s", addr.String()) | ||
| } | ||
| alias := AddGlobal(mod, ctx.Int64Type(), "address") | ||
| alias.SetInitializer(addr) | ||
| if err := VerifyModule(mod, ReturnStatusAction); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| path := filepath.Join(t.TempDir(), "ptrtoaddr.ll") | ||
| if err := os.WriteFile(path, []byte(mod.String()), 0600); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| buf, err := NewMemoryBufferFromFile(path) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| roundTrip, err := ctx.ParseIR(buf) // ParseIR consumes buf. | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| defer roundTrip.Dispose() | ||
| if err := VerifyModule(roundTrip, ReturnStatusAction); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if !strings.Contains(roundTrip.String(), "ptrtoaddr (ptr @data to i64)") { | ||
| t.Fatalf("constant expression lost during round trip:\n%s", roundTrip.String()) | ||
| } | ||
| } | ||
|
|
||
| func TestPtrToAddrDoesNotExposeProvenance(t *testing.T) { | ||
| ctx := NewContext() | ||
| defer ctx.Dispose() | ||
| mod := ctx.NewModule("provenance") | ||
| defer mod.Dispose() | ||
| mod.SetDataLayout("e-p:64:64") | ||
| b := ctx.NewBuilder() | ||
| defer b.Dispose() | ||
| exposeTy := FunctionType(ctx.VoidType(), []Type{ctx.Int64Type()}, false) | ||
| expose := AddFunction(mod, "observe_address", exposeTy) | ||
| for _, name := range []string{"address", "pointer"} { | ||
| fn := AddFunction(mod, name, FunctionType(ctx.Int32Type(), nil, false)) | ||
| b.SetInsertPointAtEnd(ctx.AddBasicBlock(fn, "entry")) | ||
| ptr := b.CreateAlloca(ctx.Int32Type(), "p") | ||
| b.CreateStore(ConstInt(ctx.Int32Type(), 7, false), ptr) | ||
| var addr Value | ||
| if name == "address" { | ||
| addr = b.CreatePtrToAddr(ptr, "addr") | ||
| } else { | ||
| addr = b.CreatePtrToInt(ptr, ctx.Int64Type(), "addr") | ||
| } | ||
| b.CreateCall(exposeTy, expose, []Value{addr}, "") | ||
| b.CreateRet(b.CreateLoad(ctx.Int32Type(), ptr, "value")) | ||
| } | ||
| options := NewPassBuilderOptions() | ||
| defer options.Dispose() | ||
| if err := mod.RunPasses("default<O2>", TargetMachine{}, options); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if err := VerifyModule(mod, ReturnStatusAction); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if ir := mod.NamedFunction("address").String(); !strings.Contains(ir, "ret i32 7") || strings.Contains(ir, "load i32") { | ||
| t.Fatalf("ptrtoaddr unexpectedly exposed provenance:\n%s", ir) | ||
| } | ||
| if ir := mod.NamedFunction("pointer").String(); !strings.Contains(ir, "load i32") { | ||
| t.Fatalf("ptrtoint control did not expose provenance:\n%s", ir) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Missing LLVM license header
Same as the header file: this
.cppis missing the standard//===- ... ===//Apache-2.0-WITH-LLVM-exception block that every other binding source in the repo carries.