Repository navigation
interp: resize ptrtoint and inttoptr results #5745
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 |
|---|---|---|
|
|
@@ -668,6 +668,29 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent | |
| // while changing the LLVM type. | ||
| // Because interp doesn't preserve the type, these operations are | ||
| // identity operations. | ||
| if inst.opcode != llvm.BitCast { | ||
| bits := int(r.pointerSize * 8) | ||
| if inst.opcode == llvm.PtrToInt { | ||
| bits = inst.llvmInst.Type().IntTypeWidth() | ||
| } | ||
| if int(operands[0].len(r)*8) != bits { | ||
|
Member
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. This still misses same-width casts of real pointers. On a 64-bit target, converting a global pointer to
Member
Author
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. Thanks @jakebailey. I tried this with The same width case is left as an identity on purpose. Keeping the pointer lets interp handle A narrower fix is to have
Member
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. Seems fine, however you want it; glad I was wrong
Member
Author
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. I opened #5748 for the |
||
| // ptrtoint and inttoptr truncate or zero-extend when sizes differ. | ||
| // https://llvm.org/docs/LangRef.html#ptrtoint-to-instruction | ||
| _, isPtr := operands[0].(pointerValue) | ||
| if raw, ok := operands[0].(rawValue); ok && raw.hasPointer() { | ||
| isPtr = true | ||
| } | ||
| if isPtr || (bits != 8 && bits != 16 && bits != 32 && bits != 64) { | ||
| err := r.runAtRuntime(fn, inst, locals, &mem, indent) | ||
| if err != nil { | ||
| return nil, mem, err | ||
| } | ||
| continue | ||
| } | ||
| locals[inst.localIndex] = makeLiteralInt(operands[0].Uint(r), bits) | ||
| continue | ||
| } | ||
| } | ||
| if r.debug { | ||
| fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", operands[0]) | ||
| } | ||
|
|
@@ -976,6 +999,10 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me | |
| } | ||
| case llvm.BitCast: | ||
| result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name) | ||
| case llvm.PtrToInt: | ||
| result = r.builder.CreatePtrToInt(operands[0], inst.llvmInst.Type(), inst.name) | ||
| case llvm.IntToPtr: | ||
| result = r.builder.CreateIntToPtr(operands[0], inst.llvmInst.Type(), inst.name) | ||
| case llvm.ExtractValue: | ||
| indices := inst.llvmInst.Indices() | ||
| // Note: the Go LLVM API doesn't support multiple indices, so simulate | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64--linux" | ||
|
|
||
| @main.v1 = global i32 0 | ||
| @main.v2 = global i64 0 | ||
| @main.v3 = global i8 0 | ||
| @main.global = global i8 0 | ||
| @main.v4 = global i8 0 | ||
| @main.v5 = global i8 0 | ||
| @main.v6 = global { i8, i8 } { i8 ptrtoint (ptr @main.global to i8), i8 7 } | ||
| @main.v7 = global i8 0 | ||
| @main.v8 = global i1 0 | ||
|
|
||
| define void @runtime.initAll() unnamed_addr { | ||
| entry: | ||
| call void @main.init() | ||
| ret void | ||
| } | ||
|
|
||
| define internal void @main.init() unnamed_addr { | ||
| entry: | ||
| ; Narrow the receiver from a pointer, like an interface method thunk. | ||
| %v1 = call i32 @main.narrow.id.unpack(ptr inttoptr (i8 1 to ptr)) | ||
| store i32 %v1, ptr @main.v1 | ||
|
|
||
| ; Widen a narrow integer through a pointer. | ||
| %ptr = inttoptr i16 -1 to ptr | ||
| %v2 = ptrtoint ptr %ptr to i64 | ||
| store i64 %v2, ptr @main.v2 | ||
|
|
||
| ; A real pointer can't be truncated at compile time. | ||
| %v3 = ptrtoint ptr @main.global to i8 | ||
| store i8 %v3, ptr @main.v3 | ||
|
|
||
| ; The same conversions as constant expressions. | ||
| store i8 ptrtoint (ptr inttoptr (i64 258 to ptr) to i8), ptr @main.v4 | ||
| store i8 ptrtoint (ptr @main.global to i8), ptr @main.v5 | ||
|
|
||
| ; A global whose initializer can't be computed at compile time. | ||
| %v7 = load i8, ptr getelementptr inbounds (i8, ptr @main.v6, i64 1) | ||
| store i8 %v7, ptr @main.v7 | ||
|
|
||
| ; A result narrower than its allocation size is left for runtime. | ||
| store i1 ptrtoint (ptr inttoptr (i64 2 to ptr) to i1), ptr @main.v8 | ||
| ret void | ||
| } | ||
|
|
||
| define internal i32 @main.narrow.id.unpack(ptr %receiver) unnamed_addr { | ||
| entry: | ||
| %unpack.int = ptrtoint ptr %receiver to i8 | ||
| %ret = call i32 @main.narrow.id(i8 %unpack.int) | ||
| ret i32 %ret | ||
| } | ||
|
|
||
| define internal i32 @main.narrow.id(i8 %h) unnamed_addr { | ||
| entry: | ||
| %cmp = icmp eq i8 %h, 1 | ||
| br i1 %cmp, label %if.then, label %if.done | ||
|
|
||
| if.then: | ||
| ret i32 10 | ||
|
|
||
| if.done: | ||
| ret i32 0 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64--linux" | ||
|
|
||
| @main.v1 = local_unnamed_addr global i32 10 | ||
| @main.v2 = local_unnamed_addr global i64 65535 | ||
| @main.v3 = local_unnamed_addr global i8 0 | ||
| @main.global = global i8 0 | ||
| @main.v4 = local_unnamed_addr global i8 2 | ||
| @main.v5 = local_unnamed_addr global i8 0 | ||
| @main.v6 = local_unnamed_addr global { i8, i8 } { i8 ptrtoint (ptr @main.global to i8), i8 7 } | ||
| @main.v7 = local_unnamed_addr global i8 0 | ||
| @main.v8 = local_unnamed_addr global i1 false | ||
|
|
||
| define void @runtime.initAll() unnamed_addr { | ||
| entry: | ||
| store i8 ptrtoint (ptr @main.global to i8), ptr @main.v3, align 1 | ||
| store i8 ptrtoint (ptr @main.global to i8), ptr @main.v5, align 1 | ||
| %v7 = load i8, ptr getelementptr inbounds (i8, ptr @main.v6, i64 1), align 1 | ||
| store i8 %v7, ptr @main.v7, align 1 | ||
| store i1 ptrtoint (ptr inttoptr (i64 2 to ptr) to i1), ptr @main.v8, align 1 | ||
| ret void | ||
| } |
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.
Good catch. Constant expressions now truncate or zero-extend too. If a real pointer would need resizing, the value falls back to runtime, and a global with such an initializer is treated as external. Added test cases for both.
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.
@dkegel-fastly the requested changes have been made.