Skip to content

Commit 2fd669c

Browse files
committed
all: remove pointer ElementType calls
This is needed for opaque pointers, which are enabled by default in LLVM 15.
1 parent 971f019 commit 2fd669c

File tree

17 files changed

+82
-93
lines changed

17 files changed

+82
-93
lines changed

builder/build.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
411411
return errors.New("global not found: " + globalName)
412412
}
413413
name := global.Name()
414-
newGlobal := llvm.AddGlobal(mod, global.Type().ElementType(), name+".tmp")
414+
newGlobal := llvm.AddGlobal(mod, global.GlobalValueType(), name+".tmp")
415415
global.ReplaceAllUsesWith(newGlobal)
416416
global.EraseFromParentAsGlobal()
417417
newGlobal.SetName(name)
@@ -1127,7 +1127,7 @@ func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) erro
11271127

11281128
// A strin is a {ptr, len} pair. We need these types to build the
11291129
// initializer.
1130-
initializerType := global.Type().ElementType()
1130+
initializerType := global.GlobalValueType()
11311131
if initializerType.TypeKind() != llvm.StructTypeKind || initializerType.StructName() == "" {
11321132
return fmt.Errorf("%s: not a string", globalName)
11331133
}

compiler/asserts.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (b *builder) createSliceToArrayPointerCheck(sliceLen llvm.Value, arrayLen i
9191

9292
// createUnsafeSliceCheck inserts a runtime check used for unsafe.Slice. This
9393
// function must panic if the ptr/len parameters are invalid.
94-
func (b *builder) createUnsafeSliceCheck(ptr, len llvm.Value, lenType *types.Basic) {
94+
func (b *builder) createUnsafeSliceCheck(ptr, len llvm.Value, elementType llvm.Type, lenType *types.Basic) {
9595
// From the documentation of unsafe.Slice:
9696
// > At run time, if len is negative, or if ptr is nil and len is not
9797
// > zero, a run-time panic occurs.
@@ -105,7 +105,7 @@ func (b *builder) createUnsafeSliceCheck(ptr, len llvm.Value, lenType *types.Bas
105105

106106
// Determine the maximum slice size, and therefore the maximum value of the
107107
// len parameter.
108-
maxSize := b.maxSliceSize(ptr.Type().ElementType())
108+
maxSize := b.maxSliceSize(elementType)
109109
maxSizeValue := llvm.ConstInt(len.Type(), maxSize, false)
110110

111111
// Do the check. By using unsigned greater than for the length check, signed

compiler/calls.go

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const maxFieldsPerParam = 3
2020
type paramInfo struct {
2121
llvmType llvm.Type
2222
name string // name, possibly with suffixes for e.g. struct fields
23-
flags paramFlags
23+
elemSize uint64 // size of pointer element type, or 0 if this isn't a pointer
2424
}
2525

2626
// paramFlags identifies parameter attributes for flags. Most importantly, it
@@ -96,13 +96,7 @@ func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType
9696
// failed to expand this parameter: too many fields
9797
}
9898
// TODO: split small arrays
99-
return []paramInfo{
100-
{
101-
llvmType: t,
102-
name: name,
103-
flags: getTypeFlags(goType),
104-
},
105-
}
99+
return []paramInfo{c.getParamInfo(t, name, goType)}
106100
}
107101

108102
// expandFormalParamOffsets returns a list of offsets from the start of an
@@ -152,7 +146,6 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value {
152146
// Try to flatten a struct type to a list of types. Returns a 1-element slice
153147
// with the passed in type if this is not possible.
154148
func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo {
155-
typeFlags := getTypeFlags(goType)
156149
switch t.TypeKind() {
157150
case llvm.StructTypeKind:
158151
var paramInfos []paramInfo
@@ -183,40 +176,37 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType
183176
}
184177
}
185178
subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i))
186-
for i := range subInfos {
187-
subInfos[i].flags |= typeFlags
188-
}
189179
paramInfos = append(paramInfos, subInfos...)
190180
}
191181
return paramInfos
192182
default:
193-
return []paramInfo{
194-
{
195-
llvmType: t,
196-
name: name,
197-
flags: typeFlags,
198-
},
199-
}
183+
return []paramInfo{c.getParamInfo(t, name, goType)}
200184
}
201185
}
202186

203-
// getTypeFlags returns the type flags for a given type. It will not recurse
204-
// into sub-types (such as in structs).
205-
func getTypeFlags(t types.Type) paramFlags {
206-
if t == nil {
207-
return 0
187+
// getParamInfo collects information about a parameter. For example, if this
188+
// parameter is pointer-like, it will also store the element type for the
189+
// dereferenceable_or_null attribute.
190+
func (c *compilerContext) getParamInfo(t llvm.Type, name string, goType types.Type) paramInfo {
191+
info := paramInfo{
192+
llvmType: t,
193+
name: name,
208194
}
209-
switch t.Underlying().(type) {
210-
case *types.Pointer:
211-
// Pointers in Go must either point to an object or be nil.
212-
return paramIsDeferenceableOrNull
213-
case *types.Chan, *types.Map:
214-
// Channels and maps are implemented as pointers pointing to some
215-
// object, and follow the same rules as *types.Pointer.
216-
return paramIsDeferenceableOrNull
217-
default:
218-
return 0
195+
if goType != nil {
196+
switch underlying := goType.Underlying().(type) {
197+
case *types.Pointer:
198+
// Pointers in Go must either point to an object or be nil.
199+
info.elemSize = c.targetData.TypeAllocSize(c.getLLVMType(underlying.Elem()))
200+
case *types.Chan:
201+
// Channels are implemented simply as a *runtime.channel.
202+
info.elemSize = c.targetData.TypeAllocSize(c.getLLVMRuntimeType("channel"))
203+
case *types.Map:
204+
// Maps are similar to channels: they are implemented as a
205+
// *runtime.hashmap.
206+
info.elemSize = c.targetData.TypeAllocSize(c.getLLVMRuntimeType("hashmap"))
207+
}
219208
}
209+
return info
220210
}
221211

222212
// extractSubfield extracts a field from a struct, or returns null if this is

compiler/compiler.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
862862
if files, ok := c.embedGlobals[member.Name()]; ok {
863863
c.createEmbedGlobal(member, global, files)
864864
} else if !info.extern {
865-
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
865+
global.SetInitializer(llvm.ConstNull(global.GlobalValueType()))
866866
global.SetVisibility(llvm.HiddenVisibility)
867867
if info.section != "" {
868868
global.SetSection(info.section)
@@ -1405,7 +1405,7 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
14051405
b.CreateRet(b.getValue(instr.Results[0]))
14061406
} else {
14071407
// Multiple return values. Put them all in a struct.
1408-
retVal := llvm.ConstNull(b.llvmFn.Type().ElementType().ReturnType())
1408+
retVal := llvm.ConstNull(b.llvmFn.GlobalValueType().ReturnType())
14091409
for i, result := range instr.Results {
14101410
val := b.getValue(result)
14111411
retVal = b.CreateInsertValue(retVal, val, i, "")
@@ -1444,7 +1444,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
14441444
elemsBuf := b.CreateExtractValue(elems, 0, "append.elemsBuf")
14451445
elemsPtr := b.CreateBitCast(elemsBuf, b.i8ptrType, "append.srcPtr")
14461446
elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen")
1447-
elemType := srcBuf.Type().ElementType()
1447+
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
14481448
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
14491449
result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcPtr, elemsPtr, srcLen, srcCap, elemsLen, elemSize}, "append.new")
14501450
newPtr := b.CreateExtractValue(result, 0, "append.newPtr")
@@ -1497,7 +1497,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
14971497
srcLen := b.CreateExtractValue(src, 1, "copy.srcLen")
14981498
dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray")
14991499
srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray")
1500-
elemType := dstBuf.Type().ElementType()
1500+
elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem())
15011501
dstBuf = b.CreateBitCast(dstBuf, b.i8ptrType, "copy.dstPtr")
15021502
srcBuf = b.CreateBitCast(srcBuf, b.i8ptrType, "copy.srcPtr")
15031503
elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false)
@@ -1637,7 +1637,8 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
16371637
b.uintptrType,
16381638
b.uintptrType,
16391639
}, false))
1640-
b.createUnsafeSliceCheck(ptr, len, argTypes[1].Underlying().(*types.Basic))
1640+
elementType := b.getLLVMType(argTypes[0].Underlying().(*types.Pointer).Elem())
1641+
b.createUnsafeSliceCheck(ptr, len, elementType, argTypes[1].Underlying().(*types.Basic))
16411642
if len.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
16421643
// Too small, zero-extend len.
16431644
len = b.CreateZExt(len, b.uintptrType, "")
@@ -1712,7 +1713,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
17121713
// Eventually we might be able to eliminate this special case
17131714
// entirely. For details, see:
17141715
// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
1715-
calleeType = llvm.FunctionType(callee.Type().ElementType().ReturnType(), nil, false)
1716+
calleeType = llvm.FunctionType(callee.GlobalValueType().ReturnType(), nil, false)
17161717
callee = llvm.ConstBitCast(callee, llvm.PointerType(calleeType, b.funcPtrAddrSpace))
17171718
}
17181719
case *ssa.MakeClosure:
@@ -3095,7 +3096,7 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
30953096
}
30963097
case token.MUL: // *x, dereference pointer
30973098
valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Pointer).Elem())
3098-
if b.targetData.TypeAllocSize(x.Type().ElementType()) == 0 {
3099+
if b.targetData.TypeAllocSize(valueType) == 0 {
30993100
// zero-length data
31003101
return llvm.ConstNull(valueType), nil
31013102
} else if strings.HasSuffix(unop.X.String(), "$funcaddr") {

compiler/func.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type {
7373
return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false)
7474
}
7575

76-
// getRawFuncType returns a LLVM function pointer type for a given signature.
76+
// getRawFuncType returns a LLVM function type for a given signature.
7777
func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type {
7878
// Get the return type.
7979
var returnType llvm.Type

compiler/interface.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
8686
if _, ok := typ.Underlying().(*types.Pointer); !ok {
8787
ptrTo = c.getTypeCode(types.NewPointer(typ))
8888
}
89-
globalValue := llvm.ConstNull(global.Type().ElementType())
89+
globalValue := llvm.ConstNull(global.GlobalValueType())
9090
if !references.IsNil() {
9191
globalValue = c.builder.CreateInsertValue(globalValue, references, 0, "")
9292
}
@@ -533,7 +533,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFnType
533533

534534
receiverValue := b.emitPointerUnpack(wrapper.Param(0), []llvm.Type{receiverType})[0]
535535
params := append(b.expandFormalParam(receiverValue), wrapper.Params()[1:]...)
536-
if llvmFn.Type().ElementType().ReturnType().TypeKind() == llvm.VoidTypeKind {
536+
if llvmFnType.ReturnType().TypeKind() == llvm.VoidTypeKind {
537537
b.CreateCall(llvmFnType, llvmFn, params, "")
538538
b.CreateRetVoid()
539539
} else {

compiler/ircheck/check.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special
7070
return fmt.Errorf("failed to verify element type of array type %s: %s", t.String(), err.Error())
7171
}
7272
case llvm.PointerTypeKind:
73-
// check underlying type
74-
if err := c.checkType(t.ElementType(), checked, specials); err != nil {
75-
return fmt.Errorf("failed to verify underlying type of pointer type %s: %s", t.String(), err.Error())
76-
}
73+
// Pointers can't be checked in an opaque pointer world.
7774
case llvm.VectorTypeKind:
7875
// check element type
7976
if err := c.checkType(t.ElementType(), checked, specials); err != nil {

compiler/symbol.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
8383
// Add an extra parameter as the function context. This context is used in
8484
// closures and bound methods, but should be optimized away when not used.
8585
if !info.exported {
86-
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0})
86+
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", elemSize: 0})
8787
}
8888

8989
var paramTypes []llvm.Type
@@ -112,17 +112,8 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
112112

113113
dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
114114
for i, info := range paramInfos {
115-
if info.flags&paramIsDeferenceableOrNull == 0 {
116-
continue
117-
}
118-
if info.llvmType.TypeKind() == llvm.PointerTypeKind {
119-
el := info.llvmType.ElementType()
120-
size := c.targetData.TypeAllocSize(el)
121-
if size == 0 {
122-
// dereferenceable_or_null(0) appears to be illegal in LLVM.
123-
continue
124-
}
125-
dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, size)
115+
if info.elemSize != 0 {
116+
dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, info.elemSize)
126117
llvmFn.AddAttributeAtIndex(i+1, dereferenceableOrNull)
127118
}
128119
}

interp/compiler.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
209209
case llvm.Alloca:
210210
// Alloca allocates stack space for local variables.
211211
numElements := r.getValue(inst.llvmInst.Operand(0)).(literalValue).value.(uint32)
212-
elementSize := r.targetData.TypeAllocSize(inst.llvmInst.Type().ElementType())
212+
elementSize := r.targetData.TypeAllocSize(inst.llvmInst.AllocatedType())
213213
inst.operands = []value{
214214
literalValue{elementSize * uint64(numElements)},
215215
}
@@ -218,17 +218,17 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
218218
inst.name = llvmInst.Name()
219219
ptr := llvmInst.Operand(0)
220220
n := llvmInst.OperandsCount()
221-
elementType := ptr.Type().ElementType()
221+
elementType := llvmInst.GEPSourceElementType()
222222
// gep: [source ptr, dest value size, pairs of indices...]
223223
inst.operands = []value{
224224
r.getValue(ptr),
225-
literalValue{r.targetData.TypeAllocSize(llvmInst.Type().ElementType())},
226225
r.getValue(llvmInst.Operand(1)),
227226
literalValue{r.targetData.TypeAllocSize(elementType)},
228227
}
229228
for i := 2; i < n; i++ {
230229
operand := r.getValue(llvmInst.Operand(i))
231-
if elementType.TypeKind() == llvm.StructTypeKind {
230+
switch elementType.TypeKind() {
231+
case llvm.StructTypeKind:
232232
index := operand.(literalValue).value.(uint32)
233233
elementOffset := r.targetData.ElementOffset(elementType, int(index))
234234
// Encode operands in a special way. The elementOffset
@@ -242,12 +242,15 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
242242
// runtime.
243243
inst.operands = append(inst.operands, literalValue{elementOffset}, literalValue{^uint64(index)})
244244
elementType = elementType.StructElementTypes()[index]
245-
} else {
245+
case llvm.ArrayTypeKind:
246246
elementType = elementType.ElementType()
247247
elementSize := r.targetData.TypeAllocSize(elementType)
248248
elementSizeOperand := literalValue{elementSize}
249249
// Add operand * elementSizeOperand bytes to the pointer.
250250
inst.operands = append(inst.operands, operand, elementSizeOperand)
251+
default:
252+
// This should be unreachable.
253+
panic("unknown type: " + elementType.String())
251254
}
252255
}
253256
case llvm.BitCast, llvm.IntToPtr, llvm.PtrToInt:
@@ -267,10 +270,12 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
267270
case llvm.StructTypeKind:
268271
offset += r.targetData.ElementOffset(indexingType, int(index))
269272
indexingType = indexingType.StructElementTypes()[index]
270-
default: // ArrayTypeKind
273+
case llvm.ArrayTypeKind:
271274
indexingType = indexingType.ElementType()
272275
elementSize := r.targetData.TypeAllocSize(indexingType)
273276
offset += elementSize * uint64(index)
277+
default:
278+
panic("unknown type kind") // unreachable
274279
}
275280
}
276281
size := r.targetData.TypeAllocSize(inst.llvmInst.Type())
@@ -290,10 +295,12 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
290295
case llvm.StructTypeKind:
291296
offset += r.targetData.ElementOffset(indexingType, int(index))
292297
indexingType = indexingType.StructElementTypes()[index]
293-
default: // ArrayTypeKind
298+
case llvm.ArrayTypeKind:
294299
indexingType = indexingType.ElementType()
295300
elementSize := r.targetData.TypeAllocSize(indexingType)
296301
offset += elementSize * uint64(index)
302+
default:
303+
panic("unknown type kind") // unreachable
297304
}
298305
}
299306
// insertvalue [agg, elt, byteOffset]

interp/interp.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
156156
if obj.constant {
157157
continue // constant buffers can't have been modified
158158
}
159-
initializer, err := obj.buffer.toLLVMValue(obj.llvmGlobal.Type().ElementType(), &mem)
159+
initializer, err := obj.buffer.toLLVMValue(obj.llvmGlobal.GlobalValueType(), &mem)
160160
if err == errInvalidPtrToIntSize {
161161
// This can happen when a previous interp run did not have the
162162
// correct LLVM type for a global and made something up. In that
@@ -190,7 +190,7 @@ func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
190190
if err != nil {
191191
return err
192192
}
193-
if checks && initializer.Type() != obj.llvmGlobal.Type().ElementType() {
193+
if checks && initializer.Type() != obj.llvmGlobal.GlobalValueType() {
194194
panic("initializer type mismatch")
195195
}
196196
obj.llvmGlobal.SetInitializer(initializer)
@@ -213,7 +213,7 @@ func RunFunc(fn llvm.Value, timeout time.Duration, debug bool) error {
213213
r.pkgName = initName[:len(initName)-len(".init")]
214214

215215
// Create new function with the interp result.
216-
newFn := llvm.AddFunction(mod, fn.Name()+".tmp", fn.Type().ElementType())
216+
newFn := llvm.AddFunction(mod, fn.Name()+".tmp", fn.GlobalValueType())
217217
newFn.SetLinkage(fn.Linkage())
218218
newFn.SetVisibility(fn.Visibility())
219219
entry := mod.Context().AddBasicBlock(newFn, "entry")
@@ -263,11 +263,11 @@ func RunFunc(fn llvm.Value, timeout time.Duration, debug bool) error {
263263
if obj.constant {
264264
continue // constant, so can't have been modified
265265
}
266-
initializer, err := obj.buffer.toLLVMValue(obj.llvmGlobal.Type().ElementType(), &mem)
266+
initializer, err := obj.buffer.toLLVMValue(obj.llvmGlobal.GlobalValueType(), &mem)
267267
if err != nil {
268268
return err
269269
}
270-
if checks && initializer.Type() != obj.llvmGlobal.Type().ElementType() {
270+
if checks && initializer.Type() != obj.llvmGlobal.GlobalValueType() {
271271
panic("initializer type mismatch")
272272
}
273273
obj.llvmGlobal.SetInitializer(initializer)

interp/interpreter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
655655
// GetElementPtr does pointer arithmetic, changing the offset of the
656656
// pointer into the underlying object.
657657
var offset uint64
658-
for i := 2; i < len(operands); i += 2 {
658+
for i := 1; i < len(operands); i += 2 {
659659
index := operands[i].Uint()
660660
elementSize := operands[i+1].Uint()
661661
if int64(elementSize) < 0 {

0 commit comments

Comments
 (0)