interp: always run atomic and volatile loads/stores at runtime
Этот коммит содержится в:
родитель
0ed34e3cb0
коммит
aa053b5fb0
3 изменённых файлов: 61 добавлений и 2 удалений
|
@ -532,7 +532,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
size := operands[1].(literalValue).value.(uint64)
|
size := operands[1].(literalValue).value.(uint64)
|
||||||
if mem.hasExternalStore(ptr) {
|
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalStore(ptr) {
|
||||||
// If there could be an external store (for example, because a
|
// If there could be an external store (for example, because a
|
||||||
// pointer to the object was passed to a function that could not
|
// pointer to the object was passed to a function that could not
|
||||||
// be interpreted at compile time) then the load must be done at
|
// be interpreted at compile time) then the load must be done at
|
||||||
|
@ -562,7 +562,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
if mem.hasExternalLoadOrStore(ptr) {
|
if inst.llvmInst.IsVolatile() || inst.llvmInst.Ordering() != llvm.AtomicOrderingNotAtomic || mem.hasExternalLoadOrStore(ptr) {
|
||||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, err
|
return nil, mem, err
|
||||||
|
@ -936,12 +936,18 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
|
||||||
if inst.llvmInst.IsVolatile() {
|
if inst.llvmInst.IsVolatile() {
|
||||||
result.SetVolatile(true)
|
result.SetVolatile(true)
|
||||||
}
|
}
|
||||||
|
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
|
||||||
|
result.SetOrdering(ordering)
|
||||||
|
}
|
||||||
case llvm.Store:
|
case llvm.Store:
|
||||||
mem.markExternalStore(operands[1])
|
mem.markExternalStore(operands[1])
|
||||||
result = r.builder.CreateStore(operands[0], operands[1])
|
result = r.builder.CreateStore(operands[0], operands[1])
|
||||||
if inst.llvmInst.IsVolatile() {
|
if inst.llvmInst.IsVolatile() {
|
||||||
result.SetVolatile(true)
|
result.SetVolatile(true)
|
||||||
}
|
}
|
||||||
|
if ordering := inst.llvmInst.Ordering(); ordering != llvm.AtomicOrderingNotAtomic {
|
||||||
|
result.SetOrdering(ordering)
|
||||||
|
}
|
||||||
case llvm.BitCast:
|
case llvm.BitCast:
|
||||||
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
|
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
|
||||||
case llvm.ExtractValue:
|
case llvm.ExtractValue:
|
||||||
|
|
31
interp/testdata/revert.ll
предоставленный
31
interp/testdata/revert.ll
предоставленный
|
@ -7,6 +7,9 @@ declare void @externalCall(i64)
|
||||||
@bar.knownAtRuntime = global i64 0
|
@bar.knownAtRuntime = global i64 0
|
||||||
@baz.someGlobal = external global [3 x {i64, i32}]
|
@baz.someGlobal = external global [3 x {i64, i32}]
|
||||||
@baz.someInt = global i32 0
|
@baz.someInt = global i32 0
|
||||||
|
@x.atomicNum = global i32 0
|
||||||
|
@x.volatileNum = global i32 0
|
||||||
|
@y.ready = global i32 0
|
||||||
|
|
||||||
define void @runtime.initAll() unnamed_addr {
|
define void @runtime.initAll() unnamed_addr {
|
||||||
entry:
|
entry:
|
||||||
|
@ -14,6 +17,8 @@ entry:
|
||||||
call void @foo.init(i8* undef, i8* undef)
|
call void @foo.init(i8* undef, i8* undef)
|
||||||
call void @bar.init(i8* undef, i8* undef)
|
call void @bar.init(i8* undef, i8* undef)
|
||||||
call void @main.init(i8* undef, i8* undef)
|
call void @main.init(i8* undef, i8* undef)
|
||||||
|
call void @x.init(i8* undef, i8* undef)
|
||||||
|
call void @y.init(i8* undef, i8* undef)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,3 +46,29 @@ entry:
|
||||||
call void @externalCall(i64 3)
|
call void @externalCall(i64 3)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
define internal void @x.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
; Test atomic and volatile memory accesses.
|
||||||
|
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
|
||||||
|
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
|
||||||
|
store i32 %x, i32* @x.atomicNum
|
||||||
|
%y = load volatile i32, i32* @x.volatileNum
|
||||||
|
store volatile i32 %y, i32* @x.volatileNum
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @y.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
entry:
|
||||||
|
br label %loop
|
||||||
|
|
||||||
|
loop:
|
||||||
|
; Test a wait-loop.
|
||||||
|
; This function must be reverted.
|
||||||
|
%val = load atomic i32, i32* @y.ready seq_cst, align 4
|
||||||
|
%ready = icmp eq i32 %val, 1
|
||||||
|
br i1 %ready, label %end, label %loop
|
||||||
|
|
||||||
|
end:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
22
interp/testdata/revert.out.ll
предоставленный
22
interp/testdata/revert.out.ll
предоставленный
|
@ -5,6 +5,9 @@ target triple = "x86_64--linux"
|
||||||
@bar.knownAtRuntime = local_unnamed_addr global i64 0
|
@bar.knownAtRuntime = local_unnamed_addr global i64 0
|
||||||
@baz.someGlobal = external local_unnamed_addr global [3 x { i64, i32 }]
|
@baz.someGlobal = external local_unnamed_addr global [3 x { i64, i32 }]
|
||||||
@baz.someInt = local_unnamed_addr global i32 0
|
@baz.someInt = local_unnamed_addr global i32 0
|
||||||
|
@x.atomicNum = local_unnamed_addr global i32 0
|
||||||
|
@x.volatileNum = global i32 0
|
||||||
|
@y.ready = local_unnamed_addr global i32 0
|
||||||
|
|
||||||
declare void @externalCall(i64) local_unnamed_addr
|
declare void @externalCall(i64) local_unnamed_addr
|
||||||
|
|
||||||
|
@ -15,6 +18,12 @@ entry:
|
||||||
%val = load i64, i64* @foo.knownAtRuntime, align 8
|
%val = load i64, i64* @foo.knownAtRuntime, align 8
|
||||||
store i64 %val, i64* @bar.knownAtRuntime, align 8
|
store i64 %val, i64* @bar.knownAtRuntime, align 8
|
||||||
call void @externalCall(i64 3)
|
call void @externalCall(i64 3)
|
||||||
|
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
|
||||||
|
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
|
||||||
|
store i32 %x, i32* @x.atomicNum, align 4
|
||||||
|
%y = load volatile i32, i32* @x.volatileNum, align 4
|
||||||
|
store volatile i32 %y, i32* @x.volatileNum, align 4
|
||||||
|
call fastcc void @y.init(i8* undef, i8* undef)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,3 +35,16 @@ define internal fastcc void @foo.init(i8* %context, i8* %parentHandle) unnamed_a
|
||||||
define internal fastcc void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
define internal fastcc void @baz.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
unreachable
|
unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define internal fastcc void @y.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
entry:
|
||||||
|
br label %loop
|
||||||
|
|
||||||
|
loop: ; preds = %loop, %entry
|
||||||
|
%val = load atomic i32, i32* @y.ready seq_cst, align 4
|
||||||
|
%ready = icmp eq i32 %val, 1
|
||||||
|
br i1 %ready, label %end, label %loop
|
||||||
|
|
||||||
|
end: ; preds = %loop
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче