Skip to content

Commit 6709900

Browse files
authored
New feature flag to allow for stack backtrace/unwind (#8703)
* New feature flag to keep the frame pointer for LLVM-generated functions. * Update Python bindings Target flags and generator emit options.
1 parent 8e965e7 commit 6709900

File tree

6 files changed

+66
-39
lines changed

6 files changed

+66
-39
lines changed

python_bindings/src/halide/halide_/PyEnums.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ void define_enums(py::module &m) {
116116
py::enum_<Target::Feature>(m, "TargetFeature")
117117
.value("JIT", Target::Feature::JIT)
118118
.value("Debug", Target::Feature::Debug)
119+
.value("EnableBacktraces", Target::Feature::EnableBacktraces)
119120
.value("NoAsserts", Target::Feature::NoAsserts)
120121
.value("NoBoundsQuery", Target::Feature::NoBoundsQuery)
121122
.value("SSE41", Target::Feature::SSE41)
@@ -135,6 +136,10 @@ void define_enums(py::module &m) {
135136
.value("CUDACapability35", Target::Feature::CUDACapability35)
136137
.value("CUDACapability50", Target::Feature::CUDACapability50)
137138
.value("CUDACapability61", Target::Feature::CUDACapability61)
139+
.value("CUDACapability70", Target::Feature::CUDACapability70)
140+
.value("CUDACapability75", Target::Feature::CUDACapability75)
141+
.value("CUDACapability80", Target::Feature::CUDACapability80)
142+
.value("CUDACapability86", Target::Feature::CUDACapability86)
138143
.value("OpenCL", Target::Feature::OpenCL)
139144
.value("CLDoubles", Target::Feature::CLDoubles)
140145
.value("CLHalf", Target::Feature::CLHalf)
@@ -146,8 +151,9 @@ void define_enums(py::module &m) {
146151
.value("Metal", Target::Feature::Metal)
147152
.value("CPlusPlusMangling", Target::Feature::CPlusPlusMangling)
148153
.value("LargeBuffers", Target::Feature::LargeBuffers)
149-
.value("HVX", Target::Feature::HVX)
154+
.value("HexagonDma", Target::Feature::HexagonDma)
150155
.value("HVX_128", Target::Feature::HVX_128)
156+
.value("HVX", Target::Feature::HVX)
151157
.value("HVX_v62", Target::Feature::HVX_v62)
152158
.value("HVX_v65", Target::Feature::HVX_v65)
153159
.value("HVX_v66", Target::Feature::HVX_v66)
@@ -159,24 +165,25 @@ void define_enums(py::module &m) {
159165
.value("AVX512_KNL", Target::Feature::AVX512_KNL)
160166
.value("AVX512_Skylake", Target::Feature::AVX512_Skylake)
161167
.value("AVX512_Cannonlake", Target::Feature::AVX512_Cannonlake)
168+
.value("AVX512_SapphireRapids", Target::Feature::AVX512_SapphireRapids)
162169
.value("AVX512_Zen4", Target::Feature::AVX512_Zen4)
163170
.value("AVX512_Zen5", Target::Feature::AVX512_Zen5)
164-
.value("AVX512_SapphireRapids", Target::Feature::AVX512_SapphireRapids)
165171
.value("TraceLoads", Target::Feature::TraceLoads)
166172
.value("TraceStores", Target::Feature::TraceStores)
167173
.value("TraceRealizations", Target::Feature::TraceRealizations)
174+
.value("TracePipeline", Target::Feature::TracePipeline)
168175
.value("D3D12Compute", Target::Feature::D3D12Compute)
169176
.value("StrictFloat", Target::Feature::StrictFloat)
170177
.value("TSAN", Target::Feature::TSAN)
171178
.value("ASAN", Target::Feature::ASAN)
172179
.value("CheckUnsafePromises", Target::Feature::CheckUnsafePromises)
173-
.value("HexagonDma", Target::Feature::HexagonDma)
174180
.value("EmbedBitcode", Target::Feature::EmbedBitcode)
175181
.value("EnableLLVMLoopOpt", Target::Feature::EnableLLVMLoopOpt)
176182
.value("WasmMvpOnly", Target::Feature::WasmMvpOnly)
177183
.value("WasmSimd128", Target::Feature::WasmSimd128)
178184
.value("WasmThreads", Target::Feature::WasmThreads)
179185
.value("WasmBulkMemory", Target::Feature::WasmBulkMemory)
186+
.value("WebGPU", Target::Feature::WebGPU)
180187
.value("SVE", Target::Feature::SVE)
181188
.value("SVE2", Target::Feature::SVE2)
182189
.value("ARMDotProd", Target::Feature::ARMDotProd)
@@ -221,6 +228,7 @@ void define_enums(py::module &m) {
221228
.value("bitcode", OutputFileType::bitcode)
222229
.value("c_header", OutputFileType::c_header)
223230
.value("c_source", OutputFileType::c_source)
231+
.value("compiler_log", OutputFileType::compiler_log)
224232
.value("cpp_stub", OutputFileType::cpp_stub)
225233
.value("featurization", OutputFileType::featurization)
226234
.value("function_info_header", OutputFileType::function_info_header)
@@ -233,8 +241,10 @@ void define_enums(py::module &m) {
233241
.value("schedule", OutputFileType::schedule)
234242
.value("static_library", OutputFileType::static_library)
235243
.value("stmt", OutputFileType::stmt)
244+
.value("conceptual_stmt", OutputFileType::conceptual_stmt)
236245
.value("stmt_html", OutputFileType::stmt_html)
237-
.value("compiler_log", OutputFileType::compiler_log);
246+
.value("conceptual_stmt_html", OutputFileType::conceptual_stmt_html)
247+
.value("device_code", OutputFileType::device_code);
238248

239249
py::enum_<Partition>(m, "Partition")
240250
.value("Auto", Partition::Auto)

src/CodeGen_Internal.cpp

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -588,17 +588,27 @@ std::optional<std::string> get_md_string(llvm::Metadata *value) {
588588
}
589589
return std::nullopt;
590590
}
591+
592+
bool get_modflag_bool(const llvm::Module &mod, const char *flag, bool or_default = false) {
593+
return get_md_bool(mod.getModuleFlag(flag)).value_or(or_default);
594+
}
595+
596+
int get_modflag_int(const llvm::Module &mod, const char *flag, int or_default = 0) {
597+
return get_md_int(mod.getModuleFlag(flag)).value_or(or_default);
598+
}
599+
600+
std::string get_modflag_string(const llvm::Module &mod, const char *flag, const std::string &or_default = {}) {
601+
return get_md_string(mod.getModuleFlag(flag)).value_or(or_default);
602+
}
603+
591604
} // namespace
592605

593606
void get_target_options(const llvm::Module &module, llvm::TargetOptions &options) {
594-
bool use_soft_float_abi =
595-
get_md_bool(module.getModuleFlag("halide_use_soft_float_abi")).value_or(false);
596-
std::string mabi =
597-
get_md_string(module.getModuleFlag("halide_mabi")).value_or(std::string{});
607+
bool use_soft_float_abi = get_modflag_bool(module, "halide_use_soft_float_abi");
608+
std::string mabi = get_modflag_string(module, "halide_mabi");
598609

599610
// FIXME: can this be migrated into `set_function_attributes_from_halide_target_options()`?
600-
bool per_instruction_fast_math_flags =
601-
get_md_bool(module.getModuleFlag("halide_per_instruction_fast_math_flags")).value_or(false);
611+
bool per_instruction_fast_math_flags = get_modflag_bool(module, "halide_per_instruction_fast_math_flags");
602612

603613
options = llvm::TargetOptions();
604614
options.AllowFPOpFusion = per_instruction_fast_math_flags ? llvm::FPOpFusion::Strict : llvm::FPOpFusion::Fast;
@@ -610,8 +620,7 @@ void get_target_options(const llvm::Module &module, llvm::TargetOptions &options
610620
options.GuaranteedTailCallOpt = false;
611621
options.FunctionSections = true;
612622
options.UseInitArray = true;
613-
options.FloatABIType =
614-
use_soft_float_abi ? llvm::FloatABI::Soft : llvm::FloatABI::Hard;
623+
options.FloatABIType = use_soft_float_abi ? llvm::FloatABI::Soft : llvm::FloatABI::Hard;
615624
#if LLVM_VERSION >= 190
616625
options.MCOptions.X86RelaxRelocations = false;
617626
#else
@@ -627,7 +636,8 @@ void clone_target_options(const llvm::Module &from, llvm::Module &to) {
627636

628637
// Clone bool metadata
629638
for (const char *s : {"halide_use_soft_float_abi",
630-
"halide_use_pic"}) {
639+
"halide_use_pic",
640+
"halide_enable_backtraces"}) {
631641
if (auto md = get_md_bool(from.getModuleFlag(s))) {
632642
to.addModuleFlag(llvm::Module::Warning, s, *md ? 1 : 0);
633643
}
@@ -658,17 +668,12 @@ std::unique_ptr<llvm::TargetMachine> make_target_machine(const llvm::Module &mod
658668
llvm::TargetOptions options;
659669
get_target_options(module, options);
660670

661-
bool use_pic =
662-
get_md_bool(module.getModuleFlag("halide_use_pic")).value_or(true);
663-
664-
bool use_large_code_model =
665-
get_md_bool(module.getModuleFlag("halide_use_large_code_model")).value_or(false);
671+
bool use_pic = get_modflag_bool(module, "halide_use_pic", true);
672+
bool use_large_code_model = get_modflag_bool(module, "halide_use_large_code_model");
666673

667674
// Get module mcpu_target and mattrs.
668-
std::string mcpu_target =
669-
get_md_string(module.getModuleFlag("halide_mcpu_target")).value_or(std::string{});
670-
std::string mattrs =
671-
get_md_string(module.getModuleFlag("halide_mattrs")).value_or(std::string{});
675+
std::string mcpu_target = get_modflag_string(module, "halide_mcpu_target");
676+
std::string mattrs = get_modflag_string(module, "halide_mattrs");
672677

673678
#if LLVM_VERSION < 200
674679
if (triple.isMacOSX() && triple.isAArch64()) {
@@ -698,18 +703,19 @@ std::unique_ptr<llvm::TargetMachine> make_target_machine(const llvm::Module &mod
698703
void set_function_attributes_from_halide_target_options(llvm::Function &fn) {
699704
llvm::Module &module = *fn.getParent();
700705

701-
std::string mcpu_target =
702-
get_md_string(module.getModuleFlag("halide_mcpu_target")).value_or(std::string{});
703-
std::string mcpu_tune =
704-
get_md_string(module.getModuleFlag("halide_mcpu_tune")).value_or(std::string{});
705-
std::string mattrs =
706-
get_md_string(module.getModuleFlag("halide_mattrs")).value_or(std::string{});
707-
int64_t vscale_range =
708-
get_md_int(module.getModuleFlag("halide_effective_vscale")).value_or(0);
706+
std::string mcpu_target = get_modflag_string(module, "halide_mcpu_target");
707+
std::string mcpu_tune = get_modflag_string(module, "halide_mcpu_tune");
708+
std::string mattrs = get_modflag_string(module, "halide_mattrs");
709+
int64_t vscale_range = get_modflag_int(module, "halide_effective_vscale");
710+
bool enable_bt = get_modflag_int(module, "halide_enable_backtraces");
709711

710712
fn.addFnAttr("target-cpu", mcpu_target);
711713
fn.addFnAttr("tune-cpu", mcpu_tune);
712714
fn.addFnAttr("target-features", mattrs);
715+
if (enable_bt) {
716+
fn.addFnAttr("frame-pointer", "all");
717+
fn.setUWTableKind(llvm::UWTableKind::Default);
718+
}
713719

714720
// Halide-generated IR is not exception-safe.
715721
// No exception should unwind out of Halide functions.

src/CodeGen_LLVM.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ void CodeGen_LLVM::init_codegen(const std::string &name) {
401401
module->setModuleIdentifier(name);
402402

403403
// Add some target specific info to the module as metadata.
404+
bool enable_bt = target.has_feature(Target::Feature::EnableBacktraces) ||
405+
target.has_feature(Target::Feature::Debug);
406+
module->addModuleFlag(llvm::Module::Warning, "halide_enable_backtraces", enable_bt ? 1 : 0);
404407
module->addModuleFlag(llvm::Module::Warning, "halide_use_soft_float_abi", use_soft_float_abi() ? 1 : 0);
405408
module->addModuleFlag(llvm::Module::Warning, "halide_mcpu_target", MDString::get(*context, mcpu_target()));
406409
module->addModuleFlag(llvm::Module::Warning, "halide_mcpu_tune", MDString::get(*context, mcpu_tune()));

src/Target.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ bool lookup_processor(const std::string &tok, Target::Processor &result) {
646646
const std::map<std::string, Target::Feature> feature_name_map = {
647647
{"jit", Target::JIT},
648648
{"debug", Target::Debug},
649+
{"enable_backtraces", Target::EnableBacktraces},
649650
{"no_asserts", Target::NoAsserts},
650651
{"no_bounds_query", Target::NoBoundsQuery},
651652
{"sse41", Target::SSE41},
@@ -1547,7 +1548,7 @@ bool Target::get_runtime_compatible_target(const Target &other, Target &result)
15471548
// (c) must match across both targets; it is an error if one target has the feature and the other doesn't
15481549

15491550
// clang-format off
1550-
const std::array<Feature, 33> union_features = {{
1551+
const std::vector<Feature> union_features = {{
15511552
// These are true union features.
15521553
CUDA,
15531554
D3D12Compute,
@@ -1592,7 +1593,7 @@ bool Target::get_runtime_compatible_target(const Target &other, Target &result)
15921593
// clang-format on
15931594

15941595
// clang-format off
1595-
const std::array<Feature, 16> intersection_features = {{
1596+
const std::vector<Feature> intersection_features = {{
15961597
ARMv7s,
15971598
AVX,
15981599
AVX2,
@@ -1613,9 +1614,10 @@ bool Target::get_runtime_compatible_target(const Target &other, Target &result)
16131614
// clang-format on
16141615

16151616
// clang-format off
1616-
const std::array<Feature, 9> matching_features = {{
1617+
const std::vector<Feature> matching_features = {{
16171618
ASAN,
16181619
Debug,
1620+
EnableBacktraces,
16191621
HexagonDma,
16201622
HVX,
16211623
MSAN,

src/Target.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct Target {
8484
enum Feature {
8585
JIT = halide_target_feature_jit,
8686
Debug = halide_target_feature_debug,
87+
EnableBacktraces = halide_target_feature_enable_backtraces,
8788
NoAsserts = halide_target_feature_no_asserts,
8889
NoBoundsQuery = halide_target_feature_no_bounds_query,
8990
SSE41 = halide_target_feature_sse41,

src/runtime/HalideRuntime.h

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,14 +1351,19 @@ extern int halide_error_vscale_invalid(void *user_context, const char *func_name
13511351
// @}
13521352

13531353
/** Optional features a compilation Target can have.
1354-
* Be sure to keep this in sync with the Feature enum in Target.h and the implementation of
1355-
* get_runtime_compatible_target in Target.cpp if you add a new feature.
1354+
*
1355+
* Be sure to keep this in sync with:
1356+
* 1. the Feature enum in Target.h,
1357+
* 2. the implementation of get_runtime_compatible_target in Target.cpp,
1358+
* 3. PyEnums.cpp,
1359+
* if you add a new feature.
13561360
*/
13571361
typedef enum halide_target_feature_t {
1358-
halide_target_feature_jit = 0, ///< Generate code that will run immediately inside the calling process.
1359-
halide_target_feature_debug, ///< Turn on debug info and output for runtime code.
1360-
halide_target_feature_no_asserts, ///< Disable all runtime checks, for slightly tighter code.
1361-
halide_target_feature_no_bounds_query, ///< Disable the bounds querying functionality.
1362+
halide_target_feature_jit = 0, ///< Generate code that will run immediately inside the calling process.
1363+
halide_target_feature_debug, ///< Turn on debug info and output for runtime code.
1364+
halide_target_feature_enable_backtraces, ///< Preserve frame pointers and include unwind tables to support accurate backtraces for debugging and profiling.
1365+
halide_target_feature_no_asserts, ///< Disable all runtime checks, for slightly tighter code.
1366+
halide_target_feature_no_bounds_query, ///< Disable the bounds querying functionality.
13621367

13631368
halide_target_feature_sse41, ///< Use SSE 4.1 and earlier instructions. Only relevant on x86.
13641369
halide_target_feature_avx, ///< Use AVX 1 instructions. Only relevant on x86.

0 commit comments

Comments
 (0)