Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/llvm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI

on: [push]

jobs:
build_llvm:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
- macOS-latest
cmake_args:
- "-DLLVM_ENABLE_PROJECTS='clang'"
steps:
- name: Setup Windows
if: startsWith(matrix.os, 'windows')
uses: tstellar/actions/setup-windows@master
with:
arch: amd64
- uses: actions/checkout@v1
with:
fetch-depth: 1
- name: Install Ninja
uses: tstellar/actions/install-ninja@master
with:
os: ${{ runner.os }}
- name: Test LLVM
uses: tstellar/actions/build-test-llvm-project@master
with:
cmake_args: -G Ninja -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}
os: ${{ runner.os }}
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2272,6 +2272,9 @@ class FunctionDecl : public DeclaratorDecl,
/// true through IsAligned.
bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const;

/// Determine if this function provides an inline implementation of a builtin.
bool isInlineBuiltinDeclaration() const;

/// Determine whether this is a destroying operator delete.
bool isDestroyingOperatorDelete() const;

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3003,6 +3003,14 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const
return Params == FPT->getNumParams();
}

bool FunctionDecl::isInlineBuiltinDeclaration() const {
if (!getBuiltinID())
return false;

const FunctionDecl *Definition;
return hasBody(Definition) && Definition->isInlineSpecified();
}

bool FunctionDecl::isDestroyingOperatorDelete() const {
// C++ P0722:
// Within a class C, a single object deallocation function with signature
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4596,8 +4596,15 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
}

static CGCallee EmitDirectCallee(CodeGenFunction &CGF, const FunctionDecl *FD) {

if (auto builtinID = FD->getBuiltinID()) {
return CGCallee::forBuiltin(builtinID, FD);
// Replaceable builtin provide their own implementation of a builtin. Unless
// we are in the builtin implementation itself, don't call the actual
// builtin. If we are in the builtin implementation, avoid trivial infinite
// recursion.
if (!FD->isInlineBuiltinDeclaration() ||
CGF.CurFn->getName() == FD->getName())
return CGCallee::forBuiltin(builtinID, FD);
}

llvm::Constant *calleePtr = EmitFunctionDeclPointer(CGF.CGM, FD);
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,11 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
else if (const auto *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());

if (FD->isInlineBuiltinDeclaration()) {
F->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoBuiltin);
}

if (FD->isReplaceableGlobalAllocationFunction()) {
// A replaceable global allocation function does not act like a builtin by
// default, only if it is invoked by a new-expression or delete-expression.
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CodeGen/memcpy-nobuiltin.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_DECL | FileCheck --check-prefix=CHECK-WITH-DECL %s
// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -UWITH_DECL | FileCheck --check-prefix=CHECK-NO-DECL %s
// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
//
// CHECK-WITH-DECL-NOT: @llvm.memcpy
// CHECK-NO-DECL: @llvm.memcpy
// CHECK-SELF-REF-DECL: @llvm.memcpy
//
#include <memcpy-nobuiltin.inc>
void test(void *dest, void const *from, size_t n) {
memcpy(dest, from, n);

static char buffer[1];
memcpy(buffer, from, 2); // expected-warning {{'memcpy' will always overflow; destination buffer has size 1, but size argument is 2}}
}
19 changes: 19 additions & 0 deletions clang/test/CodeGen/memcpy-nobuiltin.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stddef.h>
extern void *memcpy(void *dest, void const *from, size_t n);

#ifdef WITH_DECL
inline void *memcpy(void *dest, void const *from, size_t n) {
char const *ifrom = from;
char *idest = dest;
while (n--)
*idest++ = *ifrom++;
return dest;
}
#endif
#ifdef WITH_SELF_REFERENCE_DECL
inline void *memcpy(void *dest, void const *from, size_t n) {
if (n != 0)
memcpy(dest, from, n);
return dest;
}
#endif