interp: fix several bugs related to constant vs dirty values

* Loading from a dirty global must be done at runtime (!). For some
  reason this wasn't already the case.
* Global variables somehow had IsConstant() the wrong way round,
  returning the inverse from what they should.
* Do binary and logical operations at runtime if necessary, relying on
  const propagation in the IR builder.
* Don't try to interpret functions that take a dirty parameter. Call
  them at runtime.
Этот коммит содержится в:
Ayke van Laethem 2018-11-14 12:20:06 +01:00
родитель eccbd572eb
коммит 7d8b269f2e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
2 изменённых файлов: 28 добавлений и 23 удалений

Просмотреть файл

@ -38,43 +38,43 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
switch inst.InstructionOpcode() { switch inst.InstructionOpcode() {
// Standard binary operators // Standard binary operators
case llvm.Add: case llvm.Add:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstAdd(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateAdd(lhs, rhs, "")}
case llvm.FAdd: case llvm.FAdd:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstFAdd(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateFAdd(lhs, rhs, "")}
case llvm.Sub: case llvm.Sub:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstSub(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateSub(lhs, rhs, "")}
case llvm.FSub: case llvm.FSub:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstFSub(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateFSub(lhs, rhs, "")}
case llvm.Mul: case llvm.Mul:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstMul(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateMul(lhs, rhs, "")}
case llvm.FMul: case llvm.FMul:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstFMul(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateFMul(lhs, rhs, "")}
case llvm.UDiv: case llvm.UDiv:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstUDiv(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateUDiv(lhs, rhs, "")}
case llvm.SDiv: case llvm.SDiv:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstSDiv(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateSDiv(lhs, rhs, "")}
case llvm.FDiv: case llvm.FDiv:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstFDiv(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateFDiv(lhs, rhs, "")}
case llvm.URem: case llvm.URem:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstURem(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateURem(lhs, rhs, "")}
case llvm.SRem: case llvm.SRem:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstSRem(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateSRem(lhs, rhs, "")}
case llvm.FRem: case llvm.FRem:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstFRem(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateFRem(lhs, rhs, "")}
// Logical operators // Logical operators
case llvm.Shl: case llvm.Shl:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstShl(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateShl(lhs, rhs, "")}
case llvm.LShr: case llvm.LShr:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstLShr(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateLShr(lhs, rhs, "")}
case llvm.AShr: case llvm.AShr:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstAShr(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateAShr(lhs, rhs, "")}
case llvm.And: case llvm.And:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstAnd(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateAnd(lhs, rhs, "")}
case llvm.Or: case llvm.Or:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstOr(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateOr(lhs, rhs, "")}
case llvm.Xor: case llvm.Xor:
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstXor(lhs, rhs)} fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateXor(lhs, rhs, "")}
default: default:
return nil, nil, &Unsupported{inst} return nil, nil, &Unsupported{inst}
@ -90,7 +90,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
case !inst.IsALoadInst().IsNil(): case !inst.IsALoadInst().IsNil():
operand := fr.getLocal(inst.Operand(0)) operand := fr.getLocal(inst.Operand(0))
var value llvm.Value var value llvm.Value
if inst.IsVolatile() { if !operand.IsConstant() || inst.IsVolatile() {
value = fr.builder.CreateLoad(operand.Value(), inst.Name()) value = fr.builder.CreateLoad(operand.Value(), inst.Name())
} else { } else {
value = operand.Load() value = operand.Load()
@ -325,12 +325,17 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
case !callee.IsAFunction().IsNil(): case !callee.IsAFunction().IsNil():
// regular function // regular function
var params []Value var params []Value
dirtyParams := false
for i := 0; i < inst.OperandsCount()-1; i++ { for i := 0; i < inst.OperandsCount()-1; i++ {
params = append(params, fr.getLocal(inst.Operand(i))) local := fr.getLocal(inst.Operand(i))
if !local.IsConstant() {
dirtyParams = true
}
params = append(params, local)
} }
var ret Value var ret Value
scanResult := fr.Eval.hasSideEffects(callee) scanResult := fr.Eval.hasSideEffects(callee)
if scanResult.severity == sideEffectLimited { if scanResult.severity == sideEffectLimited || dirtyParams && scanResult.severity != sideEffectAll {
// Side effect is bounded. This means the operation invokes // Side effect is bounded. This means the operation invokes
// side effects (like calling an external function) but it // side effects (like calling an external function) but it
// is known at compile time which side effects it invokes. // is known at compile time which side effects it invokes.

Просмотреть файл

@ -127,9 +127,9 @@ func (v *GlobalValue) Type() llvm.Type {
// IsConstant returns true if this global is not dirty, false otherwise. // IsConstant returns true if this global is not dirty, false otherwise.
func (v *GlobalValue) IsConstant() bool { func (v *GlobalValue) IsConstant() bool {
if _, ok := v.Eval.dirtyGlobals[v.Underlying]; ok { if _, ok := v.Eval.dirtyGlobals[v.Underlying]; ok {
return true
}
return false return false
}
return true
} }
// Load returns the initializer of the global variable. // Load returns the initializer of the global variable.