diff options
-rw-r--r-- | docs/LangRef.rst | 30 | ||||
-rw-r--r-- | include/llvm/IR/Intrinsics.td | 5 | ||||
-rw-r--r-- | include/llvm/Target/TargetLowering.h | 5 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 | ||||
-rw-r--r-- | lib/Target/ARM/ARMISelLowering.h | 5 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.h | 5 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelLowering.h | 5 | ||||
-rw-r--r-- | test/CodeGen/ARM/cache-intrinsic.ll | 26 | ||||
-rw-r--r-- | test/CodeGen/Mips/cache-intrinsic.ll | 26 | ||||
-rw-r--r-- | test/CodeGen/X86/cache-intrinsic.ll | 26 |
10 files changed, 135 insertions, 0 deletions
diff --git a/docs/LangRef.rst b/docs/LangRef.rst index c959f56ef1..d18d4ebac9 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -6939,6 +6939,36 @@ is lowered to a constant 0. Note that runtime support may be conditional on the privilege-level code is running at and the host platform. +'``llvm.clear_cache``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.clear_cache(i8*, i8*) + +Overview: +""""""""" + +The '``llvm.clear_cache``' intrinsic provides access to the systemcall +that flushes the cache at the range specified. Some targets need this +to specifically flush the instruction cache when executable data changes +in memory (self-modifying code). Other targets have unified intruction +and data cache, so they don't need any calls. + +Semantics: +"""""""""" + +When directly supported, this intrinsic will either return a call to +the appropriate cache clearing system call (usually ``__clear_cache``) +when the caches are not unified (ARM, Mips) or just remove the call +altogether when they are (ex. x86_64). + +Targets must implement it directly to have either behaviour, as the +default is to bail with "Not Implemented" message. + Standard C Library Intrinsics ----------------------------- diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 94c7b50ac8..0c9cc3be3d 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -513,6 +513,11 @@ def int_convertus : Intrinsic<[llvm_anyint_ty], def int_convertuu : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; +// Clear cache intrinsic, default to ignore (ie. emit nothing) +// maps to void __clear_cache() on supporting platforms +def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], + [], "llvm.clear_cache">; + //===----------------------------------------------------------------------===// // Target-specific intrinsics //===----------------------------------------------------------------------===// diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 8f00ac8fa3..fbc8b74e9e 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -2108,6 +2108,11 @@ public: return false; } + /// Return the builtin name for the __builtin___clear_cache intrinsic + virtual const char * getClearCacheBuiltinName() const { + llvm_unreachable("Not Implemented"); + } + /// Return the type that should be used to zero or sign extend a /// zeroext/signext integer argument or return value. FIXME: Most C calling /// convention requires the return type to be promoted, but this is not true diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index bd80a503e2..639ff82ffd 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5386,6 +5386,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { (void)getControlRoot(); return 0; } + case Intrinsic::clear_cache: + return TLI->getClearCacheBuiltinName(); case Intrinsic::donothing: // ignore return 0; diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index 022945f625..5f6ea75434 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -384,6 +384,11 @@ namespace llvm { bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; + /// Clear cache library call + const char * getClearCacheBuiltinName() const { + return "__clear_cache"; + } + protected: std::pair<const TargetRegisterClass*, uint8_t> findRepresentativeClass(MVT VT) const override; diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 27492a8046..b03cccfb58 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -583,6 +583,11 @@ namespace llvm { bool MemcpyStrSrc, MachineFunction &MF) const; + /// Clear cache library call + const char * getClearCacheBuiltinName() const { + return "__clear_cache"; + } + /// isFPImmLegal - Returns true if the target can instruction select the /// specified FP immediate natively. If false, the legalizer will /// materialize the FP immediate as a load from a constant pool. diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 894cfc6d0c..ae13ca491c 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -770,6 +770,11 @@ namespace llvm { bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; + /// Intel processors have a unified instruction and data cache + const char * getClearCacheBuiltinName() const { + return 0; // nothing to do, move along. + } + /// createFastISel - This method returns a target specific FastISel object, /// or null if the target does not support "fast" ISel. FastISel *createFastISel(FunctionLoweringInfo &funcInfo, diff --git a/test/CodeGen/ARM/cache-intrinsic.ll b/test/CodeGen/ARM/cache-intrinsic.ll new file mode 100644 index 0000000000..6048917ee9 --- /dev/null +++ b/test/CodeGen/ARM/cache-intrinsic.ll @@ -0,0 +1,26 @@ +; RUN: llc %s -o - | FileCheck %s +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64" +target triple = "armv7--linux-gnueabihf" + +@buffer = global [32 x i8] c"This is a largely unused buffer\00", align 1 +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@.str1 = private unnamed_addr constant [25 x i8] c"Still, largely unused...\00", align 1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0)) + %call1 = call i8* @strcpy(i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i8* getelementptr inbounds ([25 x i8]* @.str1, i32 0, i32 0)) #3 + call void @llvm.clear_cache(i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i8* getelementptr inbounds (i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i32 32)) #3 + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0)) + ret i32 0 +} + +; CHECK: __clear_cache + +declare i32 @printf(i8*, ...) + +declare i8* @strcpy(i8*, i8*) + +declare void @llvm.clear_cache(i8*, i8*) diff --git a/test/CodeGen/Mips/cache-intrinsic.ll b/test/CodeGen/Mips/cache-intrinsic.ll new file mode 100644 index 0000000000..2fa4115895 --- /dev/null +++ b/test/CodeGen/Mips/cache-intrinsic.ll @@ -0,0 +1,26 @@ +; RUN: llc %s -o - | FileCheck %s +target datalayout = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64" +target triple = "mips--linux-gnu" + +@buffer = global [32 x i8] c"This is a largely unused buffer\00", align 1 +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@.str1 = private unnamed_addr constant [25 x i8] c"Still, largely unused...\00", align 1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0)) + %call1 = call i8* @strcpy(i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i8* getelementptr inbounds ([25 x i8]* @.str1, i32 0, i32 0)) #3 + call void @llvm.clear_cache(i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i8* getelementptr inbounds (i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i32 32)) #3 + %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0)) + ret i32 0 +} + +; CHECK: __clear_cache + +declare i32 @printf(i8*, ...) + +declare i8* @strcpy(i8*, i8*) + +declare void @llvm.clear_cache(i8*, i8*) diff --git a/test/CodeGen/X86/cache-intrinsic.ll b/test/CodeGen/X86/cache-intrinsic.ll new file mode 100644 index 0000000000..3091b5ff31 --- /dev/null +++ b/test/CodeGen/X86/cache-intrinsic.ll @@ -0,0 +1,26 @@ +; RUN: llc %s -o - | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@buffer = global [32 x i8] c"This is a largely unused buffer\00", align 16 +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@.str1 = private unnamed_addr constant [25 x i8] c"Still, largely unused...\00", align 1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0)) + %call1 = call i8* @strcpy(i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i8* getelementptr inbounds ([25 x i8]* @.str1, i32 0, i32 0)) #3 + call void @llvm.clear_cache(i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i8* getelementptr inbounds (i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0), i32 32)) #3 + %call3 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([32 x i8]* @buffer, i32 0, i32 0)) + ret i32 0 +} + +; CHECK-NOT: __clear_cache + +declare i32 @printf(i8*, ...) + +declare i8* @strcpy(i8*, i8*) + +declare void @llvm.clear_cache(i8*, i8*) |