diff --git a/IRBindings.cpp b/IRBindings.cpp index be0a466..1a80406 100644 --- a/IRBindings.cpp +++ b/IRBindings.cpp @@ -16,6 +16,7 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -50,6 +51,11 @@ void LLVMSetMetadata2(LLVMValueRef Inst, unsigned KindID, LLVMMetadataRef MD) { unwrap(Inst)->setMetadata(KindID, N); } +void LLVMGoReplaceIncomingBlock(LLVMValueRef Phi, LLVMBasicBlockRef Old, + LLVMBasicBlockRef New) { + unwrap(Phi)->replaceIncomingBlockWith(unwrap(Old), unwrap(New)); +} + void LLVMGoSetCurrentDebugLocation(LLVMBuilderRef Bref, unsigned Line, unsigned Col, LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt) { diff --git a/IRBindings.h b/IRBindings.h index 80552de..b14fca5 100644 --- a/IRBindings.h +++ b/IRBindings.h @@ -43,6 +43,9 @@ void LLVMAddNamedMetadataOperand2(LLVMModuleRef M, const char *name, LLVMMetadataRef Val); void LLVMSetMetadata2(LLVMValueRef Inst, unsigned KindID, LLVMMetadataRef MD); +void LLVMGoReplaceIncomingBlock(LLVMValueRef Phi, LLVMBasicBlockRef Old, + LLVMBasicBlockRef New); + void LLVMGoSetCurrentDebugLocation(LLVMBuilderRef Bref, unsigned Line, unsigned Col, LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt); diff --git a/ir.go b/ir.go index d770b9d..d9f786b 100644 --- a/ir.go +++ b/ir.go @@ -1260,6 +1260,9 @@ func (v Value) IncomingBlock(i int) (bb BasicBlock) { bb.C = C.LLVMGetIncomingBlock(v.C, C.unsigned(i)) return } +func (v Value) ReplaceIncomingBlock(old, new BasicBlock) { + C.LLVMGoReplaceIncomingBlock(v.C, old.C, new.C) +} // Operations on inline assembly func InlineAsm(t Type, asmString, constraints string, hasSideEffects, isAlignStack bool, dialect InlineAsmDialect, canThrow bool) (rv Value) { diff --git a/ir_test.go b/ir_test.go index a912aec..7f06988 100644 --- a/ir_test.go +++ b/ir_test.go @@ -18,6 +18,40 @@ import ( "testing" ) +func TestReplaceIncomingBlock(t *testing.T) { + ctx := NewContext() + defer ctx.Dispose() + mod := ctx.NewModule("phi-incoming-block") + defer mod.Dispose() + b := ctx.NewBuilder() + defer b.Dispose() + + fn := AddFunction(mod, "f", FunctionType(ctx.Int32Type(), nil, false)) + entry := ctx.AddBasicBlock(fn, "entry") + old := ctx.AddBasicBlock(fn, "old") + replacement := ctx.AddBasicBlock(fn, "replacement") + merge := ctx.AddBasicBlock(fn, "merge") + + b.SetInsertPointAtEnd(entry) + b.CreateBr(replacement) + b.SetInsertPointAtEnd(old) + b.CreateRet(ConstInt(ctx.Int32Type(), 0, false)) + b.SetInsertPointAtEnd(replacement) + b.CreateBr(merge) + b.SetInsertPointAtEnd(merge) + phi := b.CreatePHI(ctx.Int32Type(), "value") + phi.AddIncoming([]Value{ConstInt(ctx.Int32Type(), 7, false)}, []BasicBlock{old}) + b.CreateRet(phi) + + phi.ReplaceIncomingBlock(old, replacement) + if got := phi.IncomingBlock(0); got != replacement { + t.Fatalf("incoming block = %v, want replacement", got) + } + if err := VerifyModule(mod, ReturnStatusAction); err != nil { + t.Fatalf("module verification failed: %v\n%s", err, mod.String()) + } +} + func testAttribute(t *testing.T, name string) { ctx := NewContext() mod := ctx.NewModule("")