Skip to content

Commit 0c6c7b9

Browse files
wsmosesCopilot
andauthored
WIP: make backtrace (#2718)
* WIP: make backtrace * Initial plan * Implement emit_backtrace in C++ and use it in copy_lower_to_upper Co-authored-by: wsmoses <1260124+wsmoses@users.noreply.github.com> * fix * Update runtime inactive error message tests for backtrace newline (#2724) * Initial plan * Update tests: change [79 x i8] to [80 x i8] for puts error message string Co-authored-by: wsmoses <1260124+wsmoses@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: wsmoses <1260124+wsmoses@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: wsmoses <1260124+wsmoses@users.noreply.github.com>
1 parent eb3bff1 commit 0c6c7b9

8 files changed

Lines changed: 100 additions & 11 deletions

File tree

enzyme/Enzyme/Utils.cpp

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,73 @@ Constant *getString(Module &M, StringRef Str) {
828828
return ConstantExpr::getInBoundsGetElementPtr(s->getType(), gv, Idxs);
829829
}
830830

831+
void emit_backtrace(llvm::Instruction *inst, llvm::raw_ostream &ss) {
832+
SmallPtrSet<llvm::Instruction *, 8> visited;
833+
while (true) {
834+
if (visited.contains(inst))
835+
break;
836+
visited.insert(inst);
837+
838+
// Print debug info for this instruction
839+
if (auto dbgLoc = inst->getDebugLoc()) {
840+
auto *loc = dbgLoc.get();
841+
while (loc) {
842+
if (auto *scope = loc->getScope()) {
843+
StringRef name = scope->getName();
844+
// Remove trailing semicolons (Julia-style function name decoration)
845+
while (!name.empty() && name.back() == ';')
846+
name = name.drop_back();
847+
if (auto *file = scope->getFile()) {
848+
StringRef dir = file->getDirectory();
849+
StringRef fn = file->getFilename();
850+
ss << " in '" << name << "' at ";
851+
if (!dir.empty())
852+
ss << dir << "/";
853+
ss << fn << ":" << loc->getLine() << "\n";
854+
} else {
855+
ss << " in '" << name << "' at unknown:" << loc->getLine() << "\n";
856+
}
857+
}
858+
loc = loc->getInlinedAt();
859+
}
860+
}
861+
862+
// Move up the call chain
863+
Function *f = inst->getParent()->getParent();
864+
865+
// Collect callers with debug info
866+
SmallVector<CallInst *, 4> callersWithDbg;
867+
for (auto *U : f->users()) {
868+
auto *CI = dyn_cast<CallInst>(U);
869+
if (!CI)
870+
continue;
871+
if (!CI->getDebugLoc())
872+
continue;
873+
callersWithDbg.push_back(CI);
874+
}
875+
876+
if (callersWithDbg.empty())
877+
break;
878+
879+
// Deduplicate by debug location MDNode
880+
SmallVector<CallInst *, 4> uniqueCallSites;
881+
SmallPtrSet<const MDNode *, 4> seenMD;
882+
for (auto *CI : callersWithDbg) {
883+
if (seenMD.insert(CI->getDebugLoc().getAsMDNode()).second)
884+
uniqueCallSites.push_back(CI);
885+
}
886+
887+
if (uniqueCallSites.size() > 1) {
888+
ss << " (multiple call sites)\n";
889+
break;
890+
} else if (uniqueCallSites.size() == 1) {
891+
inst = uniqueCallSites[0];
892+
continue;
893+
}
894+
break;
895+
}
896+
}
897+
831898
void ErrorIfRuntimeInactive(llvm::IRBuilder<> &B, llvm::Value *primal,
832899
llvm::Value *shadow, const char *Message,
833900
llvm::DebugLoc &&loc, llvm::Instruction *orig) {
@@ -892,9 +959,17 @@ void ErrorIfRuntimeInactive(llvm::IRBuilder<> &B, llvm::Value *primal,
892959
EB.CreateRetVoid();
893960
}
894961

962+
std::string Message2 = Message;
963+
if (!CustomRuntimeInactiveError) {
964+
std::string str;
965+
raw_string_ostream ss(str);
966+
ss << Message << "\n";
967+
emit_backtrace(orig, ss);
968+
Message2 = ss.str();
969+
}
895970
Value *args[] = {B.CreatePointerCast(primal, getInt8PtrTy(M.getContext())),
896971
B.CreatePointerCast(shadow, getInt8PtrTy(M.getContext())),
897-
getString(M, Message)};
972+
getString(M, Message2)};
898973
auto call = B.CreateCall(F, args);
899974
call->setDebugLoc(loc);
900975
}
@@ -4138,7 +4213,12 @@ llvm::Value *EmitNoDerivativeError(const std::string &message,
41384213
auto &M = *inst.getParent()->getParent()->getParent();
41394214
FunctionType *FT = FunctionType::get(Type::getInt32Ty(M.getContext()),
41404215
{getInt8PtrTy(M.getContext())}, false);
4141-
auto msg = getString(M, message);
4216+
std::string str;
4217+
raw_string_ostream ss(str);
4218+
ss << message << "\n";
4219+
emit_backtrace(&inst, ss);
4220+
auto msg = getString(M, ss.str());
4221+
;
41424222
auto PutsF = M.getOrInsertFunction("puts", FT);
41434223
Builder2.CreateCall(PutsF, msg);
41444224

@@ -4173,7 +4253,12 @@ bool EmitNoDerivativeError(const std::string &message, Value *todiff,
41734253
auto &M = *context.ip->GetInsertBlock()->getParent()->getParent();
41744254
FunctionType *FT = FunctionType::get(Type::getInt32Ty(M.getContext()),
41754255
{getInt8PtrTy(M.getContext())}, false);
4176-
auto msg = getString(M, message);
4256+
std::string str;
4257+
raw_string_ostream ss(str);
4258+
ss << message << "\n";
4259+
if (auto inst = dyn_cast<Instruction>(todiff))
4260+
emit_backtrace(inst, ss);
4261+
auto msg = getString(M, ss.str());
41774262
auto PutsF = M.getOrInsertFunction("puts", FT);
41784263
context.ip->CreateCall(PutsF, msg);
41794264

@@ -4206,7 +4291,11 @@ void EmitNoTypeError(const std::string &message, llvm::Instruction &inst,
42064291
auto &M = *inst.getParent()->getParent()->getParent();
42074292
FunctionType *FT = FunctionType::get(Type::getInt32Ty(M.getContext()),
42084293
{getInt8PtrTy(M.getContext())}, false);
4209-
auto msg = getString(M, message);
4294+
std::string str;
4295+
raw_string_ostream ss(str);
4296+
ss << message << "\n";
4297+
emit_backtrace(&inst, ss);
4298+
auto msg = getString(M, ss.str());
42104299
auto PutsF = M.getOrInsertFunction("puts", FT);
42114300
Builder2.CreateCall(PutsF, msg);
42124301

enzyme/test/Enzyme/ForwardMode/globalfn.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ attributes #4 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disa
9393
; CHECK-NEXT: br i1 %2, label %error.i, label %__enzyme_runtimeinactiveerr.exit
9494

9595
; CHECK: error.i: ; preds = %entry
96-
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str.2, i32 0, i32 0))
96+
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str.2, i32 0, i32 0))
9797
; CHECK-NEXT: call void @exit(i32 1)
9898
; CHECK-NEXT: unreachable
9999

enzyme/test/Enzyme/ForwardModeVector/globalfn.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ attributes #4 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disa
106106
; CHECK-NEXT: br i1 %8, label %error.i, label %__enzyme_runtimeinactiveerr.exit
107107

108108
; CHECK: error.i: ; preds = %entry
109-
; CHECK-NEXT: %{{.*}} = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str.3, i32 0, i32 0))
109+
; CHECK-NEXT: %{{.*}} = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str.3, i32 0, i32 0))
110110
; CHECK-NEXT: call void @exit(i32 1)
111111
; CHECK-NEXT: unreachable
112112

enzyme/test/Enzyme/ReverseMode/bitcastfn.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ attributes #8 = { noreturn nounwind "correctly-rounded-divide-sqrt-fp-math"="fal
344344
; CHECK-NEXT: br i1 %2, label %error.i, label %__enzyme_runtimeinactiveerr.exit
345345

346346
; CHECK: error.i: ; preds = %entry
347-
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str.1, i32 0, i32 0))
347+
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str.1, i32 0, i32 0))
348348
; CHECK-NEXT: call void @exit(i32 1)
349349
; CHECK-NEXT: unreachable
350350

enzyme/test/Enzyme/ReverseMode/callshadowar.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ declare void @__enzyme_autodiff(...)
7171
; CHECK-NEXT: br i1 %[[i5]], label %error.i, label %__enzyme_runtimeinactiveerr.exit
7272

7373
; CHECK: error.i: ; preds = %entry
74-
; CHECK-NEXT: %[[i6:.+]] = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str, i32 0, i32 0))
74+
; CHECK-NEXT: %[[i6:.+]] = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str, i32 0, i32 0))
7575
; CHECK-NEXT: call void @exit(i32 1)
7676
; CHECK-NEXT: unreachable
7777

enzyme/test/Enzyme/ReverseMode/callvalue.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ attributes #2 = { nounwind }
7474
; CHECK-NEXT: br i1 %2, label %error.i, label %__enzyme_runtimeinactiveerr.exit
7575

7676
; CHECK: error.i: ; preds = %entry
77-
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str, i32 0, i32 0))
77+
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str, i32 0, i32 0))
7878
; CHECK-NEXT: call void @exit(i32 1)
7979
; CHECK-NEXT: unreachable
8080

enzyme/test/Enzyme/ReverseMode/globalfn.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ attributes #4 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disa
112112
; CHECK-NEXT: br i1 %2, label %error.i, label %__enzyme_runtimeinactiveerr.exit
113113

114114
; CHECK: error.i: ; preds = %entry
115-
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str.2, i32 0, i32 0))
115+
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str.2, i32 0, i32 0))
116116
; CHECK-NEXT: call void @exit(i32 1)
117117
; CHECK-NEXT: unreachable
118118

enzyme/test/Enzyme/ReverseMode/indirectcst.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ entry:
2424
; CHECK-NEXT: br i1 %2, label %error.i, label %__enzyme_runtimeinactiveerr.exit
2525

2626
; CHECK: error.i: ; preds = %entry
27-
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([79 x i8], [79 x i8]* @.str, i32 0, i32 0))
27+
; CHECK-NEXT: %3 = call i32 @puts(i8* getelementptr inbounds ([80 x i8], [80 x i8]* @.str, i32 0, i32 0))
2828
; CHECK-NEXT: call void @exit(i32 1)
2929
; CHECK-NEXT: unreachable
3030

0 commit comments

Comments
 (0)