Skip to content

Commit 3193ef7

Browse files
pccAlexisPerry
authored andcommitted
CodeGen, IR: Add target-{cpu,features} attributes to functions created via createWithDefaultAttr().
Functions created with createWithDefaultAttr() need to have the correct target-{cpu,features} attributes to avoid miscompilations such as using the wrong relocation type to access globals (missing tagged-globals feature), clobbering registers specified via -ffixed-* (missing reserve-* feature), and so on. There's already a number of attributes copied from the module flags onto functions created by createWithDefaultAttr(). I don't think module flags are the right choice for the target attributes because we don't need the conflict resolution logic between modules with different target attributes, nor does it seem sensible to add it: there's no unambiguously "correct" set of target attributes when merging two modules with different attributes, and nor should there be; it's perfectly valid for two modules to be compiled with different target attributes, that's the whole reason why they are per-function. This also implies that it's unnecessary to serialize the attributes in bitcode, which implies that they shouldn't be stored on the module. We can also observe that for the most part, createWithDefaultAttr() is called from compiler passes such as sanitizers, coverage and profiling passes that are part of the compile time pipeline, not the LTO pipeline. This hints at a solution: we need to store the attributes in a non-serialized location associated with the ambient compilation context. Therefore in this patch I elected to store the attributes on the LLVMContext. There are calls to createWithDefaultAttr() in the NVPTX and AMDGPU backends, and those calls would happen at LTO time. For those callers, the bug still potentially exists and it would be necessary to refactor them to create the functions at compile time if this issue is relevant on those platforms. Fixes llvm#93633. Reviewers: fmayer, MaskRay, eugenis Reviewed By: MaskRay Pull Request: llvm#96721
1 parent 2ae3545 commit 3193ef7

10 files changed

+75
-7
lines changed

clang/lib/CodeGen/CodeGenAction.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) {
299299
Ctx.setDiagnosticHandler(std::make_unique<ClangDiagnosticHandler>(
300300
CodeGenOpts, this));
301301

302+
Ctx.setDefaultTargetCPU(TargetOpts.CPU);
303+
Ctx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ","));
304+
302305
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
303306
setupLLVMOptimizationRemarks(
304307
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,
@@ -1205,6 +1208,9 @@ void CodeGenAction::ExecuteAction() {
12051208
Ctx.setDiagnosticHandler(
12061209
std::make_unique<ClangDiagnosticHandler>(CodeGenOpts, &Result));
12071210

1211+
Ctx.setDefaultTargetCPU(TargetOpts.CPU);
1212+
Ctx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ","));
1213+
12081214
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
12091215
setupLLVMOptimizationRemarks(
12101216
Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses,

clang/test/CodeGen/asan-frame-pointer.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ int global;
88

99
// NONE: define internal void @asan.module_ctor() #[[#ATTR:]] {
1010
// NONE: define internal void @asan.module_dtor() #[[#ATTR]] {
11-
// NONE: attributes #[[#ATTR]] = { nounwind }
11+
// NONE: attributes #[[#ATTR]] = { nounwind
1212

1313
// NONLEAF: define internal void @asan.module_ctor() #[[#ATTR:]] {
1414
// NONLEAF: define internal void @asan.module_dtor() #[[#ATTR]] {
15-
// NONLEAF: attributes #[[#ATTR]] = { nounwind "frame-pointer"="non-leaf" }
15+
// NONLEAF: attributes #[[#ATTR]] = { nounwind "frame-pointer"="non-leaf"
1616

1717
// ALL: define internal void @asan.module_ctor() #[[#ATTR:]] {
1818
// ALL: define internal void @asan.module_dtor() #[[#ATTR]] {
19-
// ALL: attributes #[[#ATTR]] = { nounwind "frame-pointer"="all" }
19+
// ALL: attributes #[[#ATTR]] = { nounwind "frame-pointer"="all"

clang/test/CodeGen/asan-globals.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ void func() {
6767
// CHECK-NEXT: call void @__asan_unregister_globals
6868
// CHECK-NEXT: ret void
6969

70-
// CHECK: attributes #[[#ATTR]] = { nounwind }
70+
// CHECK: attributes #[[#ATTR]] = { nounwind
7171

7272
/// If -fasynchronous-unwind-tables, set the module flag "uwtable". ctor/dtor
7373
/// will thus get the uwtable attribute.
7474
// RUN: %clang_cc1 -emit-llvm -fsanitize=address -funwind-tables=2 -o - %s | FileCheck %s --check-prefixes=UWTABLE
7575
// UWTABLE: define internal void @asan.module_dtor() #[[#ATTR:]] {
76-
// UWTABLE: attributes #[[#ATTR]] = { nounwind uwtable }
76+
// UWTABLE: attributes #[[#ATTR]] = { nounwind uwtable
7777
// UWTABLE: ![[#]] = !{i32 7, !"uwtable", i32 2}
7878

7979
// IGNORELIST-SRC: @{{.*}}extra_global{{.*}} ={{.*}} global
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %clang_cc1 -emit-llvm -coverage-notes-file=test.gcno -coverage-data-file=test.gcda -triple aarch64-linux-android30 -target-cpu generic -target-feature +tagged-globals -fsanitize=hwaddress %s -o %t
2+
// RUN: FileCheck %s < %t
3+
4+
// CHECK: define internal void @__llvm_gcov_writeout() unnamed_addr [[ATTR:#[0-9]+]]
5+
// CHECK: define internal void @__llvm_gcov_reset() unnamed_addr [[ATTR]]
6+
// CHECK: define internal void @__llvm_gcov_init() unnamed_addr [[ATTR]]
7+
// CHECK: define internal void @hwasan.module_ctor() [[ATTR2:#[0-9]+]]
8+
// CHECK: attributes [[ATTR]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals"
9+
// CHECK: attributes [[ATTR2]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals"
10+
11+
__attribute__((weak)) int foo = 0;
12+
13+
__attribute__((weak)) void bar() {}
14+
15+
int main() {
16+
if (foo) bar();
17+
}

clang/test/CodeGen/sanitize-metadata-nosanitize.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ __attribute__((no_sanitize("all"))) int test_no_sanitize_all(int *x, int *y) {
9393
// CHECK: attributes #1 = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
9494
// CHECK: attributes #2 = { disable_sanitizer_instrumentation mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
9595
// CHECK: attributes #3 = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "no_sanitize_thread" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
96-
// CHECK: attributes #4 = { nounwind }
96+
// CHECK: attributes #4 = { nounwind "target-features"="+cx8,+mmx,+sse,+sse2,+x87" }
9797
//.
9898
// CHECK: !2 = !{!"sanmd_covered!C", !3}
9999
// CHECK: !3 = !{i64 0}

llvm/include/llvm/IR/Function.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,14 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
181181
const Twine &N, Module &M);
182182

183183
/// Creates a function with some attributes recorded in llvm.module.flags
184-
/// applied.
184+
/// and the LLVMContext applied.
185185
///
186186
/// Use this when synthesizing new functions that need attributes that would
187187
/// have been set by command line options.
188+
///
189+
/// This function should not be called from backends or the LTO pipeline. If
190+
/// it is called from one of those places, some default attributes will not be
191+
/// applied to the function.
188192
static Function *createWithDefaultAttr(FunctionType *Ty, LinkageTypes Linkage,
189193
unsigned AddrSpace,
190194
const Twine &N = "",

llvm/include/llvm/IR/LLVMContext.h

+16
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,22 @@ class LLVMContext {
327327
[[deprecated("Always returns false")]]
328328
bool supportsTypedPointers() const;
329329

330+
/// Get or set the current "default" target CPU (target-cpu function
331+
/// attribute). The intent is that compiler frontends will set this to a value
332+
/// that reflects the attribute that a function would get "by default" without
333+
/// any specific function attributes, and compiler passes will attach the
334+
/// attribute to newly created functions that are not associated with a
335+
/// particular function, such as global initializers.
336+
/// Function::createWithDefaultAttr() will create functions with this
337+
/// attribute. This function should only be called by passes that run at
338+
/// compile time and not by the backend or LTO passes.
339+
StringRef getDefaultTargetCPU();
340+
void setDefaultTargetCPU(StringRef CPU);
341+
342+
/// Similar to {get,set}DefaultTargetCPU() but for default target-features.
343+
StringRef getDefaultTargetFeatures();
344+
void setDefaultTargetFeatures(StringRef Features);
345+
330346
private:
331347
// Module needs access to the add/removeModule methods.
332348
friend class Module;

llvm/lib/IR/Function.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,12 @@ Function *Function::createWithDefaultAttr(FunctionType *Ty,
397397
}
398398
if (M->getModuleFlag("function_return_thunk_extern"))
399399
B.addAttribute(Attribute::FnRetThunkExtern);
400+
StringRef DefaultCPU = F->getContext().getDefaultTargetCPU();
401+
if (!DefaultCPU.empty())
402+
B.addAttribute("target-cpu", DefaultCPU);
403+
StringRef DefaultFeatures = F->getContext().getDefaultTargetFeatures();
404+
if (!DefaultFeatures.empty())
405+
B.addAttribute("target-features", DefaultFeatures);
400406
F->addFnAttrs(B);
401407
return F;
402408
}

llvm/lib/IR/LLVMContext.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,19 @@ void LLVMContext::setOpaquePointers(bool Enable) const {
390390
bool LLVMContext::supportsTypedPointers() const {
391391
return false;
392392
}
393+
394+
StringRef LLVMContext::getDefaultTargetCPU() {
395+
return pImpl->DefaultTargetCPU;
396+
}
397+
398+
void LLVMContext::setDefaultTargetCPU(StringRef CPU) {
399+
pImpl->DefaultTargetCPU = CPU;
400+
}
401+
402+
StringRef LLVMContext::getDefaultTargetFeatures() {
403+
return pImpl->DefaultTargetFeatures;
404+
}
405+
406+
void LLVMContext::setDefaultTargetFeatures(StringRef Features) {
407+
pImpl->DefaultTargetFeatures = Features;
408+
}

llvm/lib/IR/LLVMContextImpl.h

+3
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,9 @@ class LLVMContextImpl {
17231723
}
17241724

17251725
void deleteTrailingDbgRecords(BasicBlock *B) { TrailingDbgRecords.erase(B); }
1726+
1727+
std::string DefaultTargetCPU;
1728+
std::string DefaultTargetFeatures;
17261729
};
17271730

17281731
} // end namespace llvm

0 commit comments

Comments
 (0)