compiler: avoid load/store on zero-length data
These loads/stores probably would get optimized away anyway, but not emitting them helps the init interpreter.
Этот коммит содержится в:
родитель
2ddb6f788a
коммит
26acc89f9c
2 изменённых файлов: 31 добавлений и 10 удалений
|
@ -499,6 +499,8 @@ func (c *Compiler) Compile(mainPath string) error {
|
||||||
}
|
}
|
||||||
c.builder.CreateRetVoid()
|
c.builder.CreateRetVoid()
|
||||||
|
|
||||||
|
// Add a wrapper for the main.main function, either calling it directly or
|
||||||
|
// setting up the scheduler with it.
|
||||||
mainWrapper := c.ir.GetFunction(c.ir.Program.ImportedPackage("runtime").Members["mainWrapper"].(*ssa.Function))
|
mainWrapper := c.ir.GetFunction(c.ir.Program.ImportedPackage("runtime").Members["mainWrapper"].(*ssa.Function))
|
||||||
mainWrapper.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
mainWrapper.LLVMFn.SetLinkage(llvm.InternalLinkage)
|
||||||
mainWrapper.LLVMFn.SetUnnamedAddr(true)
|
mainWrapper.LLVMFn.SetUnnamedAddr(true)
|
||||||
|
@ -1650,6 +1652,10 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
|
||||||
|
// nothing to store
|
||||||
|
return nil
|
||||||
|
}
|
||||||
store := c.builder.CreateStore(llvmVal, llvmAddr)
|
store := c.builder.CreateStore(llvmVal, llvmAddr)
|
||||||
valType := instr.Addr.Type().(*types.Pointer).Elem()
|
valType := instr.Addr.Type().(*types.Pointer).Elem()
|
||||||
if c.ir.IsVolatile(valType) {
|
if c.ir.IsVolatile(valType) {
|
||||||
|
@ -2141,12 +2147,14 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
|
||||||
} else {
|
} else {
|
||||||
buf = c.builder.CreateAlloca(typ, expr.Comment)
|
buf = c.builder.CreateAlloca(typ, expr.Comment)
|
||||||
|
if c.targetData.TypeAllocSize(typ) != 0 {
|
||||||
zero, err := c.getZeroValue(typ)
|
zero, err := c.getZeroValue(typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
c.builder.CreateStore(zero, buf) // zero-initialize var
|
c.builder.CreateStore(zero, buf) // zero-initialize var
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return buf, nil
|
return buf, nil
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
x, err := c.parseExpr(frame, expr.X)
|
x, err := c.parseExpr(frame, expr.X)
|
||||||
|
@ -3215,12 +3223,17 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
|
||||||
}
|
}
|
||||||
case token.MUL: // *x, dereference pointer
|
case token.MUL: // *x, dereference pointer
|
||||||
valType := unop.X.Type().(*types.Pointer).Elem()
|
valType := unop.X.Type().(*types.Pointer).Elem()
|
||||||
|
if c.targetData.TypeAllocSize(x.Type().ElementType()) == 0 {
|
||||||
|
// zero-length data
|
||||||
|
return c.getZeroValue(x.Type().ElementType())
|
||||||
|
} else {
|
||||||
load := c.builder.CreateLoad(x, "")
|
load := c.builder.CreateLoad(x, "")
|
||||||
if c.ir.IsVolatile(valType) {
|
if c.ir.IsVolatile(valType) {
|
||||||
// Volatile load, for memory-mapped registers.
|
// Volatile load, for memory-mapped registers.
|
||||||
load.SetVolatile(true)
|
load.SetVolatile(true)
|
||||||
}
|
}
|
||||||
return load, nil
|
return load, nil
|
||||||
|
}
|
||||||
case token.XOR: // ^x, toggle all bits in integer
|
case token.XOR: // ^x, toggle all bits in integer
|
||||||
return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil
|
return c.builder.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -37,6 +37,8 @@ func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, global str
|
||||||
c.builder.CreateStore(val, itfValueCast)
|
c.builder.CreateStore(val, itfValueCast)
|
||||||
itfValue = c.builder.CreateBitCast(itfValueCast, c.i8ptrType, "")
|
itfValue = c.builder.CreateBitCast(itfValueCast, c.i8ptrType, "")
|
||||||
}
|
}
|
||||||
|
} else if size == 0 {
|
||||||
|
itfValue = llvm.ConstPointerNull(c.i8ptrType)
|
||||||
} else {
|
} else {
|
||||||
// Directly place the value in the interface.
|
// Directly place the value in the interface.
|
||||||
switch val.Type().TypeKind() {
|
switch val.Type().TypeKind() {
|
||||||
|
@ -152,10 +154,16 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) (llvm.Val
|
||||||
// Type assert on concrete type. Extract the underlying type from
|
// Type assert on concrete type. Extract the underlying type from
|
||||||
// the interface (but only after checking it matches).
|
// the interface (but only after checking it matches).
|
||||||
valuePtr := c.builder.CreateExtractValue(itf, 1, "typeassert.value.ptr")
|
valuePtr := c.builder.CreateExtractValue(itf, 1, "typeassert.value.ptr")
|
||||||
if c.targetData.TypeAllocSize(assertedType) > c.targetData.TypeAllocSize(c.i8ptrType) {
|
size := c.targetData.TypeAllocSize(assertedType)
|
||||||
|
if size > c.targetData.TypeAllocSize(c.i8ptrType) {
|
||||||
// Value was stored in an allocated buffer, load it from there.
|
// Value was stored in an allocated buffer, load it from there.
|
||||||
valuePtrCast := c.builder.CreateBitCast(valuePtr, llvm.PointerType(assertedType, 0), "")
|
valuePtrCast := c.builder.CreateBitCast(valuePtr, llvm.PointerType(assertedType, 0), "")
|
||||||
valueOk = c.builder.CreateLoad(valuePtrCast, "typeassert.value.ok")
|
valueOk = c.builder.CreateLoad(valuePtrCast, "typeassert.value.ok")
|
||||||
|
} else if size == 0 {
|
||||||
|
valueOk, err = c.getZeroValue(assertedType)
|
||||||
|
if err == nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Value was stored directly in the interface.
|
// Value was stored directly in the interface.
|
||||||
switch assertedType.TypeKind() {
|
switch assertedType.TypeKind() {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче