diff --git a/interp/scan.go b/interp/scan.go index add2ca3b..b8c68117 100644 --- a/interp/scan.go +++ b/interp/scan.go @@ -193,10 +193,13 @@ func (e *Eval) hasLocalSideEffects(dirtyLocals map[llvm.Value]struct{}, inst llv // Already handled in (*Eval).hasSideEffects. continue } - // But a store might also store to an alloca, in which case all uses - // of the alloca (possibly indirect through a GEP, bitcast, etc.) - // must be marked dirty. - panic("todo: store") + // This store might affect all kinds of values. While it is + // certainly possible to traverse through all of them, the easiest + // option right now is to just assume the worst and say that this + // function has side effects. + // TODO: traverse through all stores and mark all relevant allocas / + // globals dirty. + return true default: // All instructions that take 0 or more operands (1 or more if it // was a use) and produce a result. diff --git a/interp/scan_test.go b/interp/scan_test.go index 229b12ec..2150f108 100644 --- a/interp/scan_test.go +++ b/interp/scan_test.go @@ -22,6 +22,7 @@ var scanTestTable = []struct { {"readDirtyGlobal", sideEffectLimited, []string{"dirtyGlobalInt"}}, {"callFunctionPointer", sideEffectAll, []string{"functionPointer"}}, {"getDirtyPointer", sideEffectLimited, nil}, + {"storeToPointer", sideEffectLimited, nil}, } func TestScan(t *testing.T) { diff --git a/interp/testdata/scan.ll b/interp/testdata/scan.ll index 35246419..946a8a07 100644 --- a/interp/testdata/scan.ll +++ b/interp/testdata/scan.ll @@ -47,6 +47,12 @@ define i64 @readDirtyGlobal() { declare i64* @getDirtyPointer() +define void @storeToPointer() { + %ptr = call i64* @getDirtyPointer() + store i64 3, i64* %ptr + ret void +} + @functionPointer = global i64()* null define i64 @callFunctionPointer() { %fp = load i64()*, i64()** @functionPointer