From 244e181a5fa7ba3a63678b83625b71a4427a3a82 Mon Sep 17 00:00:00 2001 From: Qiu Chaofan Date: Tue, 21 Nov 2023 01:17:37 +0800 Subject: [PATCH 01/11] Enable profiler in dist-powerpc64-linux --- src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile index c88185a2000db..298282a764631 100644 --- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile @@ -26,5 +26,5 @@ ENV \ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS From e6f8edff3734ecfa55159da63343fbea3f1ee3a5 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 21 Nov 2023 13:43:11 -0500 Subject: [PATCH 02/11] Tighten up linkage settings for LLVM bindings --- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 372 ++++++++++-------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 4 +- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 6 +- 4 files changed, 206 insertions(+), 180 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 3242e78ab7e44..8d809648aca7d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -104,7 +104,7 @@ struct TimeTraceProfiler { impl TimeTraceProfiler { fn new(enabled: bool) -> Self { if enabled { - unsafe { llvm::LLVMTimeTraceProfilerInitialize() } + unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() } } TimeTraceProfiler { enabled } } @@ -113,7 +113,7 @@ impl TimeTraceProfiler { impl Drop for TimeTraceProfiler { fn drop(&mut self) { if self.enabled { - unsafe { llvm::LLVMTimeTraceProfilerFinishThread() } + unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() } } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7fc02a95be0a9..245baad261282 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -823,11 +823,7 @@ pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) - pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; extern "C" { - pub fn LLVMRustInstallFatalErrorHandler(); - pub fn LLVMRustDisableSystemDialogsOnCrash(); - // Create and destroy contexts. - pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context; pub fn LLVMContextDispose(C: &'static mut Context); pub fn LLVMGetMDKindIDInContext(C: &Context, Name: *const c_char, SLen: c_uint) -> c_uint; @@ -843,9 +839,6 @@ extern "C" { /// See Module::setModuleInlineAsm. pub fn LLVMAppendModuleInlineAsm(M: &Module, Asm: *const c_char, Len: size_t); - /// See llvm::LLVMTypeKind::getTypeID. - pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind; - // Operations on integer types pub fn LLVMInt1TypeInContext(C: &Context) -> &Type; pub fn LLVMInt8TypeInContext(C: &Context) -> &Type; @@ -879,7 +872,6 @@ extern "C" { ) -> &'a Type; // Operations on array, pointer, and vector types (sequence types) - pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type; pub fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; @@ -898,10 +890,8 @@ extern "C" { pub fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value); pub fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value); pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); - pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; pub fn LLVMIsAFunction(Val: &Value) -> Option<&Value>; - pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool; // Operations on constants of any type pub fn LLVMConstNull(Ty: &Type) -> &Value; @@ -931,13 +921,6 @@ extern "C" { pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value; pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value; pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value; - pub fn LLVMRustConstIntGetZExtValue(ConstantVal: &ConstantInt, Value: &mut u64) -> bool; - pub fn LLVMRustConstInt128Get( - ConstantVal: &ConstantInt, - SExt: bool, - high: &mut u64, - low: &mut u64, - ) -> bool; // Operations on composite constants pub fn LLVMConstStringInContext( @@ -977,12 +960,7 @@ extern "C" { // Operations on global variables, functions, and aliases (globals) pub fn LLVMIsDeclaration(Global: &Value) -> Bool; - pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage; - pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage); pub fn LLVMSetSection(Global: &Value, Section: *const c_char); - pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility; - pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility); - pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool); pub fn LLVMGetAlignment(Global: &Value) -> c_uint; pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint); pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass); @@ -991,13 +969,6 @@ extern "C" { pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; pub fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; - pub fn LLVMRustGetOrInsertGlobal<'a>( - M: &'a Module, - Name: *const c_char, - NameLen: size_t, - T: &'a Type, - ) -> &'a Value; - pub fn LLVMRustInsertPrivateGlobal<'a>(M: &'a Module, T: &'a Type) -> &'a Value; pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub fn LLVMDeleteGlobal(GlobalVar: &Value); @@ -1007,16 +978,9 @@ extern "C" { pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); - pub fn LLVMRustGetNamedValue( - M: &Module, - Name: *const c_char, - NameLen: size_t, - ) -> Option<&Value>; pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); - pub fn LLVMRustSetTailCallKind(CallInst: &Value, TKC: TailCallKind); // Operations on attributes - pub fn LLVMRustCreateAttrNoValue(C: &Context, attr: AttributeKind) -> &Attribute; pub fn LLVMCreateStringAttribute( C: &Context, Name: *const c_char, @@ -1024,31 +988,9 @@ extern "C" { Value: *const c_char, ValueLen: c_uint, ) -> &Attribute; - pub fn LLVMRustCreateAlignmentAttr(C: &Context, bytes: u64) -> &Attribute; - pub fn LLVMRustCreateDereferenceableAttr(C: &Context, bytes: u64) -> &Attribute; - pub fn LLVMRustCreateDereferenceableOrNullAttr(C: &Context, bytes: u64) -> &Attribute; - pub fn LLVMRustCreateByValAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; - pub fn LLVMRustCreateStructRetAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; - pub fn LLVMRustCreateElementTypeAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; - pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute; - pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute; - pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute; - pub fn LLVMRustCreateMemoryEffectsAttr(C: &Context, effects: MemoryEffects) -> &Attribute; // Operations on functions - pub fn LLVMRustGetOrInsertFunction<'a>( - M: &'a Module, - Name: *const c_char, - NameLen: size_t, - FunctionTy: &'a Type, - ) -> &'a Value; pub fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint); - pub fn LLVMRustAddFunctionAttributes<'a>( - Fn: &'a Value, - index: c_uint, - Attrs: *const &'a Attribute, - AttrsLen: size_t, - ); // Operations on parameters pub fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; @@ -1069,12 +1011,6 @@ extern "C" { // Operations on call sites pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint); - pub fn LLVMRustAddCallSiteAttributes<'a>( - Instr: &'a Value, - index: c_uint, - Attrs: *const &'a Attribute, - AttrsLen: size_t, - ); // Operations on load/store instructions (only) pub fn LLVMSetVolatile(MemoryAccessInst: &Value, volatile: Bool); @@ -1112,18 +1048,6 @@ extern "C" { Else: &'a BasicBlock, NumCases: c_uint, ) -> &'a Value; - pub fn LLVMRustBuildInvoke<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - Then: &'a BasicBlock, - Catch: &'a BasicBlock, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; pub fn LLVMBuildLandingPad<'a>( B: &Builder<'a>, Ty: &'a Type, @@ -1337,7 +1261,6 @@ extern "C" { pub fn LLVMBuildNeg<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value; pub fn LLVMBuildFNeg<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value; pub fn LLVMBuildNot<'a>(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value; - pub fn LLVMRustSetFastMath(Instr: &Value); // Memory pub fn LLVMBuildAlloca<'a>(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value; @@ -1485,42 +1408,6 @@ extern "C" { // Miscellaneous instructions pub fn LLVMBuildPhi<'a>(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value; - pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustBuildCall<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - ) -> &'a Value; - pub fn LLVMRustBuildMemCpy<'a>( - B: &Builder<'a>, - Dst: &'a Value, - DstAlign: c_uint, - Src: &'a Value, - SrcAlign: c_uint, - Size: &'a Value, - IsVolatile: bool, - ) -> &'a Value; - pub fn LLVMRustBuildMemMove<'a>( - B: &Builder<'a>, - Dst: &'a Value, - DstAlign: c_uint, - Src: &'a Value, - SrcAlign: c_uint, - Size: &'a Value, - IsVolatile: bool, - ) -> &'a Value; - pub fn LLVMRustBuildMemSet<'a>( - B: &Builder<'a>, - Dst: &'a Value, - DstAlign: c_uint, - Val: &'a Value, - Size: &'a Value, - IsVolatile: bool, - ) -> &'a Value; pub fn LLVMBuildSelect<'a>( B: &Builder<'a>, If: &'a Value, @@ -1568,6 +1455,202 @@ extern "C" { Name: *const c_char, ) -> &'a Value; + // Atomic Operations + pub fn LLVMBuildAtomicCmpXchg<'a>( + B: &Builder<'a>, + LHS: &'a Value, + CMP: &'a Value, + RHS: &'a Value, + Order: AtomicOrdering, + FailureOrder: AtomicOrdering, + SingleThreaded: Bool, + ) -> &'a Value; + + pub fn LLVMSetWeak(CmpXchgInst: &Value, IsWeak: Bool); + + pub fn LLVMBuildAtomicRMW<'a>( + B: &Builder<'a>, + Op: AtomicRmwBinOp, + LHS: &'a Value, + RHS: &'a Value, + Order: AtomicOrdering, + SingleThreaded: Bool, + ) -> &'a Value; + + pub fn LLVMBuildFence<'a>( + B: &Builder<'a>, + Order: AtomicOrdering, + SingleThreaded: Bool, + Name: *const c_char, + ) -> &'a Value; + + /// Writes a module to the specified path. Returns 0 on success. + pub fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int; + + /// Creates a legacy pass manager -- only used for final codegen. + pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>; + + pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>); + + pub fn LLVMGetHostCPUFeatures() -> *mut c_char; + + pub fn LLVMDisposeMessage(message: *mut c_char); + + pub fn LLVMIsMultithreaded() -> Bool; + + pub fn LLVMStructCreateNamed(C: &Context, Name: *const c_char) -> &Type; + + pub fn LLVMStructSetBody<'a>( + StructTy: &'a Type, + ElementTypes: *const &'a Type, + ElementCount: c_uint, + Packed: Bool, + ); + + pub fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; + + pub fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); + + pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; +} + +#[link(name = "llvm-wrapper", kind = "static")] +extern "C" { + pub fn LLVMRustInstallFatalErrorHandler(); + pub fn LLVMRustDisableSystemDialogsOnCrash(); + + // Create and destroy contexts. + pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context; + + /// See llvm::LLVMTypeKind::getTypeID. + pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind; + + // Operations on array, pointer, and vector types (sequence types) + pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type; + + // Operations on all values + pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); + pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool; + + // Operations on scalar constants + pub fn LLVMRustConstIntGetZExtValue(ConstantVal: &ConstantInt, Value: &mut u64) -> bool; + pub fn LLVMRustConstInt128Get( + ConstantVal: &ConstantInt, + SExt: bool, + high: &mut u64, + low: &mut u64, + ) -> bool; + + // Operations on global variables, functions, and aliases (globals) + pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage; + pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage); + pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility; + pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility); + pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool); + + // Operations on global variables + pub fn LLVMRustGetOrInsertGlobal<'a>( + M: &'a Module, + Name: *const c_char, + NameLen: size_t, + T: &'a Type, + ) -> &'a Value; + pub fn LLVMRustInsertPrivateGlobal<'a>(M: &'a Module, T: &'a Type) -> &'a Value; + pub fn LLVMRustGetNamedValue( + M: &Module, + Name: *const c_char, + NameLen: size_t, + ) -> Option<&Value>; + pub fn LLVMRustSetTailCallKind(CallInst: &Value, TKC: TailCallKind); + + // Operations on attributes + pub fn LLVMRustCreateAttrNoValue(C: &Context, attr: AttributeKind) -> &Attribute; + pub fn LLVMRustCreateAlignmentAttr(C: &Context, bytes: u64) -> &Attribute; + pub fn LLVMRustCreateDereferenceableAttr(C: &Context, bytes: u64) -> &Attribute; + pub fn LLVMRustCreateDereferenceableOrNullAttr(C: &Context, bytes: u64) -> &Attribute; + pub fn LLVMRustCreateByValAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; + pub fn LLVMRustCreateStructRetAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; + pub fn LLVMRustCreateElementTypeAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute; + pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute; + pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute; + pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute; + pub fn LLVMRustCreateMemoryEffectsAttr(C: &Context, effects: MemoryEffects) -> &Attribute; + + // Operations on functions + pub fn LLVMRustGetOrInsertFunction<'a>( + M: &'a Module, + Name: *const c_char, + NameLen: size_t, + FunctionTy: &'a Type, + ) -> &'a Value; + pub fn LLVMRustAddFunctionAttributes<'a>( + Fn: &'a Value, + index: c_uint, + Attrs: *const &'a Attribute, + AttrsLen: size_t, + ); + + // Operations on call sites + pub fn LLVMRustAddCallSiteAttributes<'a>( + Instr: &'a Value, + index: c_uint, + Attrs: *const &'a Attribute, + AttrsLen: size_t, + ); + + pub fn LLVMRustBuildInvoke<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Then: &'a BasicBlock, + Catch: &'a BasicBlock, + OpBundles: *const &OperandBundleDef<'a>, + NumOpBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + + pub fn LLVMRustSetFastMath(Instr: &Value); + + // Miscellaneous instructions + pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; + pub fn LLVMRustBuildCall<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + OpBundles: *const &OperandBundleDef<'a>, + NumOpBundles: c_uint, + ) -> &'a Value; + pub fn LLVMRustBuildMemCpy<'a>( + B: &Builder<'a>, + Dst: &'a Value, + DstAlign: c_uint, + Src: &'a Value, + SrcAlign: c_uint, + Size: &'a Value, + IsVolatile: bool, + ) -> &'a Value; + pub fn LLVMRustBuildMemMove<'a>( + B: &Builder<'a>, + Dst: &'a Value, + DstAlign: c_uint, + Src: &'a Value, + SrcAlign: c_uint, + Size: &'a Value, + IsVolatile: bool, + ) -> &'a Value; + pub fn LLVMRustBuildMemSet<'a>( + B: &Builder<'a>, + Dst: &'a Value, + DstAlign: c_uint, + Val: &'a Value, + Size: &'a Value, + IsVolatile: bool, + ) -> &'a Value; + pub fn LLVMRustBuildVectorReduceFAdd<'a>( B: &Builder<'a>, Acc: &'a Value, @@ -1623,53 +1706,11 @@ extern "C" { Order: AtomicOrdering, ) -> &'a Value; - pub fn LLVMBuildAtomicCmpXchg<'a>( - B: &Builder<'a>, - LHS: &'a Value, - CMP: &'a Value, - RHS: &'a Value, - Order: AtomicOrdering, - FailureOrder: AtomicOrdering, - SingleThreaded: Bool, - ) -> &'a Value; + pub fn LLVMRustTimeTraceProfilerInitialize(); - pub fn LLVMSetWeak(CmpXchgInst: &Value, IsWeak: Bool); + pub fn LLVMRustTimeTraceProfilerFinishThread(); - pub fn LLVMBuildAtomicRMW<'a>( - B: &Builder<'a>, - Op: AtomicRmwBinOp, - LHS: &'a Value, - RHS: &'a Value, - Order: AtomicOrdering, - SingleThreaded: Bool, - ) -> &'a Value; - - pub fn LLVMBuildFence<'a>( - B: &Builder<'a>, - Order: AtomicOrdering, - SingleThreaded: Bool, - Name: *const c_char, - ) -> &'a Value; - - /// Writes a module to the specified path. Returns 0 on success. - pub fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int; - - /// Creates a legacy pass manager -- only used for final codegen. - pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>; - - pub fn LLVMTimeTraceProfilerInitialize(); - - pub fn LLVMTimeTraceProfilerFinishThread(); - - pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char); - - pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>); - - pub fn LLVMGetHostCPUFeatures() -> *mut c_char; - - pub fn LLVMDisposeMessage(message: *mut c_char); - - pub fn LLVMIsMultithreaded() -> Bool; + pub fn LLVMRustTimeTraceProfilerFinish(FileName: *const c_char); /// Returns a string describing the last error caused by an LLVMRust* call. pub fn LLVMRustGetLastError() -> *const c_char; @@ -1680,15 +1721,6 @@ extern "C" { /// Print the statistics since static dtors aren't picking them up. pub fn LLVMRustPrintStatistics(size: *const size_t) -> *const c_char; - pub fn LLVMStructCreateNamed(C: &Context, Name: *const c_char) -> &Type; - - pub fn LLVMStructSetBody<'a>( - StructTy: &'a Type, - ElementTypes: *const &'a Type, - ElementCount: c_uint, - Packed: Bool, - ); - /// Prepares inline assembly. pub fn LLVMRustInlineAsm( Ty: &Type, @@ -1761,8 +1793,6 @@ extern "C" { ); pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool; - pub fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; - pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>; pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>); @@ -2052,8 +2082,6 @@ extern "C" { UniqueIdLen: size_t, ) -> &'a DIDerivedType; - pub fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); - pub fn LLVMRustDIBuilderCreateTemplateTypeParameter<'a>( Builder: &DIBuilder<'a>, Scope: Option<&'a DIScope>, @@ -2092,8 +2120,6 @@ extern "C" { #[allow(improper_ctypes)] pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString); - pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; - pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; pub fn LLVMRustPrintTargetCPUs( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index c86bf81fc131e..7c29bb080082c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -121,7 +121,7 @@ unsafe fn configure_llvm(sess: &Session) { } if sess.opts.unstable_opts.llvm_time_trace { - llvm::LLVMTimeTraceProfilerInitialize(); + llvm::LLVMRustTimeTraceProfilerInitialize(); } rustc_llvm::initialize_available_targets(); @@ -132,7 +132,7 @@ unsafe fn configure_llvm(sess: &Session) { pub fn time_trace_profiler_finish(file_name: &Path) { unsafe { let file_name = path_to_c_string(file_name); - llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr()); + llvm::LLVMRustTimeTraceProfilerFinish(file_name.as_ptr()); } } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 31565db1b7929..b4c8fb1a2f1d8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -60,17 +60,17 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) -extern "C" void LLVMTimeTraceProfilerInitialize() { +extern "C" void LLVMRustTimeTraceProfilerInitialize() { timeTraceProfilerInitialize( /* TimeTraceGranularity */ 0, /* ProcName */ "rustc"); } -extern "C" void LLVMTimeTraceProfilerFinishThread() { +extern "C" void LLVMRustTimeTraceProfilerFinishThread() { timeTraceProfilerFinishThread(); } -extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { +extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) { StringRef FN(FileName); std::error_code EC; raw_fd_ostream OS(FN, EC, sys::fs::CD_CreateAlways); From c089a162d80dbbcc0543649fa78ccabac569db81 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:46:17 +0100 Subject: [PATCH 03/11] Fix some unnecessary casts `x clippy compiler -Aclippy::all -Wclippy::unnecessary_cast --fix` with some manual review to ensure every fix is correct. --- compiler/rustc_codegen_ssa/src/mir/place.rs | 12 +++++------- compiler/rustc_const_eval/src/const_eval/machine.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- compiler/rustc_infer/src/infer/fudge.rs | 4 ++-- .../src/infer/lexical_region_resolve/mod.rs | 12 ++++-------- .../rustc_infer/src/infer/region_constraints/mod.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 +----- compiler/rustc_metadata/src/rmeta/table.rs | 2 +- compiler/rustc_middle/src/mir/tcx.rs | 4 +--- compiler/rustc_symbol_mangling/src/v0.rs | 2 +- 10 files changed, 18 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index eb590a45a63f2..45795a7f7359a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -474,27 +474,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_base.project_index(bx, llindex) } mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset as u64); + let lloffset = bx.cx().const_usize(offset); cg_base.project_index(bx, lloffset) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { - let lloffset = bx.cx().const_usize(offset as u64); + let lloffset = bx.cx().const_usize(offset); let lllen = cg_base.len(bx.cx()); let llindex = bx.sub(lllen, lloffset); cg_base.project_index(bx, llindex) } mir::ProjectionElem::Subslice { from, to, from_end } => { - let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64)); + let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, *elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); if subslice.layout.is_unsized() { assert!(from_end, "slice subslices should be `from_end`"); - subslice.llextra = Some(bx.sub( - cg_base.llextra.unwrap(), - bx.cx().const_usize((from as u64) + (to as u64)), - )); + subslice.llextra = + Some(bx.sub(cg_base.llextra.unwrap(), bx.cx().const_usize(from + to))); } subslice diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4b447229c5f61..5b04b37cdf514 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -485,7 +485,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, }; let ptr = ecx.allocate_ptr( - Size::from_bytes(size as u64), + Size::from_bytes(size), align, interpret::MemoryKind::Machine(MemoryKind::Heap), )?; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index d2a72f8f23385..22d94b9ca281b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1861,7 +1861,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // method yet. So create fresh variables here for those too, // if there are any. let generics = self.tcx.generics_of(method); - assert_eq!(args.len(), generics.parent_count as usize); + assert_eq!(args.len(), generics.parent_count); let xform_fn_sig = if generics.params.is_empty() { fn_sig.instantiate(self.tcx, args) diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 7e878ac06c7f2..8ca97ae1b8e5d 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize; + let idx = vid.as_usize() - self.type_vars.0.start.as_usize(); let origin = self.type_vars.1[idx]; self.infcx.next_ty_var(origin) } else { @@ -236,7 +236,7 @@ impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { if self.const_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.index() - self.const_vars.0.start.index()) as usize; + let idx = vid.index() - self.const_vars.0.start.index(); let origin = self.const_vars.1[idx]; self.infcx.next_const_var(ct.ty(), origin) } else { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 800aee1f4d3bf..b0e82a92674f4 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -681,17 +681,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for constraint in self.data.constraints.keys() { match *constraint { Constraint::VarSubVar(a_id, b_id) => { - graph.add_edge( - NodeIndex(a_id.index() as usize), - NodeIndex(b_id.index() as usize), - *constraint, - ); + graph.add_edge(NodeIndex(a_id.index()), NodeIndex(b_id.index()), *constraint); } Constraint::RegSubVar(_, b_id) => { - graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint); + graph.add_edge(dummy_source, NodeIndex(b_id.index()), *constraint); } Constraint::VarSubReg(a_id, _) => { - graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint); + graph.add_edge(NodeIndex(a_id.index()), dummy_sink, *constraint); } Constraint::RegSubReg(..) => { // this would be an edge from `dummy_source` to @@ -878,7 +874,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ) { debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); - let source_node_index = NodeIndex(source_vid.index() as usize); + let source_node_index = NodeIndex(source_vid.index()); for (_, edge) in graph.adjacent_edges(source_node_index, dir) { match edge.data { Constraint::VarSubVar(from_vid, to_vid) => { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index e888340bde3fe..260f4bc671fb4 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -316,7 +316,7 @@ impl<'tcx> RegionConstraintStorage<'tcx> { match undo_entry { AddVar(vid) => { self.var_infos.pop().unwrap(); - assert_eq!(self.var_infos.len(), vid.index() as usize); + assert_eq!(self.var_infos.len(), vid.index()); } AddConstraint(ref constraint) => { self.data.constraints.remove(constraint); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b6ffdc7378f6a..109757f8719cd 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2269,11 +2269,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap(); // Record metadata size for self-profiling - tcx.prof.artifact_size( - "crate_metadata", - "crate_metadata", - file.metadata().unwrap().len() as u64, - ); + tcx.prof.artifact_size("crate_metadata", "crate_metadata", file.metadata().unwrap().len()); } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 027994c40ab72..0d97b6b76744b 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -497,7 +497,7 @@ impl> TableBui } LazyTable::from_position_and_encoded_size( - NonZeroUsize::new(pos as usize).unwrap(), + NonZeroUsize::new(pos).unwrap(), width, self.blocks.len(), ) diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 6ab2da23a8ad1..17eb6ae274e14 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -95,9 +95,7 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Subslice { from, to, from_end } => { PlaceTy::from_ty(match self.ty.kind() { ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => { - Ty::new_array(tcx, *inner, (to - from) as u64) - } + ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from), ty::Array(inner, size) if from_end => { let size = size.eval_target_usize(tcx, param_env); let len = size - from - to; diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 01cbee3a71593..88989806997e6 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -189,7 +189,7 @@ impl<'tcx> SymbolMangler<'tcx> { self.push("N"); self.out.push(ns); print_prefix(self)?; - self.push_disambiguator(disambiguator as u64); + self.push_disambiguator(disambiguator); self.push_ident(name); Ok(()) } From e11d8d147b94043d54d0a6c8ff0bdb0568b794ca Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Fri, 17 Nov 2023 10:05:38 -0800 Subject: [PATCH 04/11] Add support for generating the EHCont section In the future Windows will enable Control-flow Enforcement Technology (CET aka Shadow Stacks). To protect the path where the context is updated during exception handling, the binary is required to enumerate valid unwind entrypoints in a dedicated section which is validated when the context is being set during exception handling. The required support for EHCONT has already been merged into LLVM, long ago. This change adds the Rust codegen option to enable it. Reference: * https://reviews.llvm.org/D40223 This also adds a new `ehcont-guard` option to the bootstrap config which enables EHCont Guard when building std. --- compiler/rustc_codegen_llvm/src/context.rs | 9 ++++++++ compiler/rustc_codegen_ssa/src/back/link.rs | 5 +++++ compiler/rustc_codegen_ssa/src/back/linker.rs | 21 +++++++++++++++++++ compiler/rustc_session/src/options.rs | 2 ++ config.example.toml | 4 ++++ src/bootstrap/src/core/builder.rs | 12 ++++++++++- src/bootstrap/src/core/config/config.rs | 3 +++ src/bootstrap/src/tests/builder.rs | 2 +- tests/codegen/ehcontguard_disabled.rs | 10 +++++++++ tests/codegen/ehcontguard_enabled.rs | 10 +++++++++ 10 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 tests/codegen/ehcontguard_disabled.rs create mode 100644 tests/codegen/ehcontguard_enabled.rs diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 242c6aed906b4..883a4b5f6fb0e 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -350,6 +350,15 @@ pub unsafe fn create_module<'ll>( 1, ); } + // Set module flag to enable Windows EHCont Guard (/guard:ehcont). + if sess.opts.cg.ehcont_guard { + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Warning, + "ehcontguard\0".as_ptr() as *const _, + 1, + ) + } // Insert `llvm.ident` metadata. // diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 33e8f352cd8ab..e571912973cc0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2378,6 +2378,11 @@ fn add_order_independent_options( cmd.control_flow_guard(); } + // OBJECT-FILES-NO, AUDIT-ORDER + if sess.opts.cg.ehcont_guard { + cmd.ehcont_guard(); + } + add_rpath_args(cmd, sess, codegen_results, out_filename); } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 09434513e31e9..73c4aa9712d0c 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -185,6 +185,7 @@ pub trait Linker { fn optimize(&mut self); fn pgo_gen(&mut self); fn control_flow_guard(&mut self); + fn ehcont_guard(&mut self); fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); @@ -605,6 +606,8 @@ impl<'a> Linker for GccLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { // MacOS linker doesn't support stripping symbols directly anymore. if self.sess.target.is_like_osx { @@ -914,6 +917,12 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/guard:cf"); } + fn ehcont_guard(&mut self) { + if self.sess.target.pointer_width == 64 { + self.cmd.arg("/guard:ehcont"); + } + } + fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { match strip { Strip::None => { @@ -1127,6 +1136,8 @@ impl<'a> Linker for EmLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { // Preserve names or generate source maps depending on debug info // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g @@ -1319,6 +1330,8 @@ impl<'a> Linker for WasmLd<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn no_crt_objects(&mut self) {} fn no_default_libraries(&mut self) {} @@ -1472,6 +1485,8 @@ impl<'a> Linker for L4Bender<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn no_crt_objects(&mut self) {} } @@ -1613,6 +1628,8 @@ impl<'a> Linker for AixLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { match strip { Strip::None => {} @@ -1835,6 +1852,8 @@ impl<'a> Linker for PtxLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {} fn subsystem(&mut self, _subsystem: &str) {} @@ -1931,6 +1950,8 @@ impl<'a> Linker for BpfLinker<'a> { fn control_flow_guard(&mut self) {} + fn ehcont_guard(&mut self) {} + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { let path = tmpdir.join("symbols"); let res: io::Result<()> = try { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b824eb51ef7be..924bd97b4d54d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1387,6 +1387,8 @@ options! { "allow the linker to link its default libraries (default: no)"), dlltool: Option = (None, parse_opt_pathbuf, [UNTRACKED], "import library generation tool (ignored except when targeting windows-gnu)"), + ehcont_guard: bool = (false, parse_bool, [TRACKED], + "generate Windows EHCont Guard tables"), embed_bitcode: bool = (true, parse_bool, [TRACKED], "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], diff --git a/config.example.toml b/config.example.toml index 170856bd97dbd..5f9ae039b252a 100644 --- a/config.example.toml +++ b/config.example.toml @@ -686,6 +686,10 @@ change-id = 116881 # This only applies from stage 1 onwards, and only for Windows targets. #control-flow-guard = false +# Enable Windows EHCont Guard checks in the standard library. +# This only applies from stage 1 onwards, and only for Windows targets. +#ehcont-guard = false + # Enable symbol-mangling-version v0. This can be helpful when profiling rustc, # as generics will be preserved in symbols (rather than erased into opaque T). # When no setting is given, the new scheme will be used when compiling the diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index c755324df1a57..de35e97848af1 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1964,6 +1964,12 @@ impl<'a> Builder<'a> { rustflags.arg("-Ccontrol-flow-guard"); } + // Same for EHCont Guard (this is not combined with the previous if-statement to make + // merges with upstream easier). + if cfg!(windows) && mode == Mode::Std && self.config.ehcont_guard && compiler.stage >= 1 { + rustflags.arg("-Cehcont-guard"); + } + // For `cargo doc` invocations, make rustdoc print the Rust version into the docs // This replaces spaces with tabs because RUSTDOCFLAGS does not // support arguments with regular spaces. Hopefully someday Cargo will @@ -2172,7 +2178,11 @@ impl<'a> Builder<'a> { } // Only execute if it's supposed to run as default - if desc.default && should_run.is_really_default() { self.ensure(step) } else { None } + if desc.default && should_run.is_really_default() { + self.ensure(step) + } else { + None + } } /// Checks if any of the "should_run" paths is in the `Builder` paths. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index fa8b0b20cec45..9ef90798590ce 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -248,6 +248,7 @@ pub struct Config { pub local_rebuild: bool, pub jemalloc: bool, pub control_flow_guard: bool, + pub ehcont_guard: bool, // dist misc pub dist_sign_folder: Option, @@ -1019,6 +1020,7 @@ define_config! { test_compare_mode: Option = "test-compare-mode", llvm_libunwind: Option = "llvm-libunwind", control_flow_guard: Option = "control-flow-guard", + ehcont_guard: Option = "ehcont-guard", new_symbol_mangling: Option = "new-symbol-mangling", profile_generate: Option = "profile-generate", profile_use: Option = "profile-use", @@ -1452,6 +1454,7 @@ impl Config { config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit; set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo); set(&mut config.control_flow_guard, rust.control_flow_guard); + set(&mut config.ehcont_guard, rust.ehcont_guard); config.llvm_libunwind_default = rust .llvm_libunwind .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); diff --git a/src/bootstrap/src/tests/builder.rs b/src/bootstrap/src/tests/builder.rs index 96139f7b099ce..744015e8e8204 100644 --- a/src/bootstrap/src/tests/builder.rs +++ b/src/bootstrap/src/tests/builder.rs @@ -1,6 +1,6 @@ use super::*; -use crate::core::config::{Config, DryRun, TargetSelection}; use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::config::{Config, DryRun, TargetSelection}; use std::thread; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { diff --git a/tests/codegen/ehcontguard_disabled.rs b/tests/codegen/ehcontguard_disabled.rs new file mode 100644 index 0000000000000..7773384e5ead4 --- /dev/null +++ b/tests/codegen/ehcontguard_disabled.rs @@ -0,0 +1,10 @@ +// compile-flags: + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() { +} + +// Ensure the module flag ehcontguard is not present +// CHECK-NOT: !"ehcontguard" diff --git a/tests/codegen/ehcontguard_enabled.rs b/tests/codegen/ehcontguard_enabled.rs new file mode 100644 index 0000000000000..5e7ea90940e74 --- /dev/null +++ b/tests/codegen/ehcontguard_enabled.rs @@ -0,0 +1,10 @@ +// compile-flags: -C ehcont_guard + +#![crate_type = "lib"] + +// A basic test function. +pub fn test() { +} + +// Ensure the module flag ehcontguard=1 is present +// CHECK: !"ehcontguard", i32 1 From d582f1092b524ed8aff86193928a1c7f871b11cf Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Fri, 17 Nov 2023 12:54:20 -0800 Subject: [PATCH 05/11] x.py fmt --- src/bootstrap/src/core/builder.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index de35e97848af1..5fd0d6a50ca6a 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2178,11 +2178,7 @@ impl<'a> Builder<'a> { } // Only execute if it's supposed to run as default - if desc.default && should_run.is_really_default() { - self.ensure(step) - } else { - None - } + if desc.default && should_run.is_really_default() { self.ensure(step) } else { None } } /// Checks if any of the "should_run" paths is in the `Builder` paths. From 9429d68842a90fec21b5bed7419840bd86baaeab Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Tue, 21 Nov 2023 14:24:23 -0800 Subject: [PATCH 06/11] convert ehcont-guard to an unstable option --- compiler/rustc_codegen_llvm/src/context.rs | 3 ++- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_session/src/options.rs | 4 ++-- tests/codegen/ehcontguard_enabled.rs | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 883a4b5f6fb0e..e6c5085cc0efd 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -350,8 +350,9 @@ pub unsafe fn create_module<'ll>( 1, ); } + // Set module flag to enable Windows EHCont Guard (/guard:ehcont). - if sess.opts.cg.ehcont_guard { + if sess.opts.unstable_opts.ehcont_guard { llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Warning, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e571912973cc0..b35ffac91b7e2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2379,7 +2379,7 @@ fn add_order_independent_options( } // OBJECT-FILES-NO, AUDIT-ORDER - if sess.opts.cg.ehcont_guard { + if sess.opts.unstable_opts.ehcont_guard { cmd.ehcont_guard(); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 924bd97b4d54d..4e669c81bf327 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1387,8 +1387,6 @@ options! { "allow the linker to link its default libraries (default: no)"), dlltool: Option = (None, parse_opt_pathbuf, [UNTRACKED], "import library generation tool (ignored except when targeting windows-gnu)"), - ehcont_guard: bool = (false, parse_bool, [TRACKED], - "generate Windows EHCont Guard tables"), embed_bitcode: bool = (true, parse_bool, [TRACKED], "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], @@ -1584,6 +1582,8 @@ options! { "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], "enables LTO for dylib crate type"), + ehcont_guard: bool = (false, parse_bool, [TRACKED], + "generate Windows EHCont Guard tables"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], diff --git a/tests/codegen/ehcontguard_enabled.rs b/tests/codegen/ehcontguard_enabled.rs index 5e7ea90940e74..03aaa342b9678 100644 --- a/tests/codegen/ehcontguard_enabled.rs +++ b/tests/codegen/ehcontguard_enabled.rs @@ -1,4 +1,4 @@ -// compile-flags: -C ehcont_guard +// compile-flags: -Z ehcont-guard #![crate_type = "lib"] From 80896cbe351aa31ddc2f805c71e7eff85495d902 Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Tue, 21 Nov 2023 14:35:02 -0800 Subject: [PATCH 07/11] update -Cehcont-guard and comment --- src/bootstrap/src/core/builder.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 5fd0d6a50ca6a..507306fd274c8 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1964,10 +1964,14 @@ impl<'a> Builder<'a> { rustflags.arg("-Ccontrol-flow-guard"); } - // Same for EHCont Guard (this is not combined with the previous if-statement to make - // merges with upstream easier). + // If EHCont Guard is enabled, pass the `-Zehcont-guard` flag to rustc when compiling the + // standard library, since this might be linked into the final outputs produced by rustc. + // Since this mitigation is only available on Windows, only enable it for the standard + // library in case the compiler is run on a non-Windows platform. + // This is not needed for stage 0 artifacts because these will only be used for building + // the stage 1 compiler. if cfg!(windows) && mode == Mode::Std && self.config.ehcont_guard && compiler.stage >= 1 { - rustflags.arg("-Cehcont-guard"); + rustflags.arg("-Zehcont-guard"); } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs From fa5ff859e610b46b924ac17df63de69c734759f8 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Tue, 7 Nov 2023 14:12:58 -0800 Subject: [PATCH 08/11] Add support to global allocation to stable-mir --- .../rustc_smir/src/rustc_internal/internal.rs | 3 +- compiler/rustc_smir/src/rustc_internal/mod.rs | 2 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 73 +++++++++++++++++-- compiler/stable_mir/src/lib.rs | 30 ++++---- compiler/stable_mir/src/mir.rs | 1 + compiler/stable_mir/src/mir/alloc.rs | 37 ++++++++++ compiler/stable_mir/src/mir/mono.rs | 25 ++++++- compiler/stable_mir/src/ty.rs | 3 +- 8 files changed, 150 insertions(+), 24 deletions(-) create mode 100644 compiler/stable_mir/src/mir/alloc.rs diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 24b1a3c63be6e..988d1d7226a18 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -7,12 +7,13 @@ use crate::rustc_smir::Tables; use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; use rustc_span::Symbol; +use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::ty::{ AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, Ty, UintTy, }; -use stable_mir::{AllocId, CrateItem, DefId}; +use stable_mir::{CrateItem, DefId}; use super::RustcInternal; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index fa75fd3076ce0..b37c9a1f632e2 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -118,7 +118,7 @@ impl<'tcx> Tables<'tcx> { self.def_ids.create_or_fetch(did) } - fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::AllocId { + fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::mir::alloc::AllocId { self.alloc_ids.create_or_fetch(aid) } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 2a9f0b4267847..509706387db67 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -17,15 +17,16 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; -use stable_mir::mir::mono::InstanceDef; +use stable_mir::mir::alloc::GlobalAlloc; +use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{ Body, ConstOperand, CopyNonOverlapping, Statement, UserTypeProjection, VarDebugInfoFragment, VariantIdx, }; use stable_mir::ty::{ - AdtDef, AdtKind, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, EarlyParamRegion, - FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, - TyKind, UintTy, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, + EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, + RigidTy, Span, TyKind, UintTy, }; use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind}; use std::cell::RefCell; @@ -318,6 +319,18 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } + fn eval_static_initializer(&self, def: StaticDef) -> Result { + let mut tables = self.0.borrow_mut(); + let def_id = def.0.internal(&mut *tables); + tables.tcx.eval_static_initializer(def_id).stable(&mut *tables) + } + + fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { + let mut tables = self.0.borrow_mut(); + let alloc_id = alloc.internal(&mut *tables); + tables.tcx.global_alloc(alloc_id).stable(&mut *tables) + } + fn usize_to_const(&self, val: u64) -> Result { let mut tables = self.0.borrow_mut(); let ty = tables.tcx.types.usize; @@ -342,7 +355,7 @@ pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell>); pub struct Tables<'tcx> { pub(crate) tcx: TyCtxt<'tcx>, pub(crate) def_ids: IndexMap, - pub(crate) alloc_ids: IndexMap, + pub(crate) alloc_ids: IndexMap, pub(crate) spans: IndexMap, pub(crate) types: IndexMap, stable_mir::ty::Ty>, pub(crate) instances: IndexMap, InstanceDef>, @@ -1590,6 +1603,14 @@ impl<'tcx> Stable<'tcx> for ty::BoundTy { } } +impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> { + type T = Allocation; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.inner().stable(tables) + } +} + impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { type T = stable_mir::ty::Allocation; @@ -1602,6 +1623,25 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { } } +impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { + type T = GlobalAlloc; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + mir::interpret::GlobalAlloc::Function(instance) => { + GlobalAlloc::Function(instance.stable(tables)) + } + mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => { + GlobalAlloc::VTable(ty.stable(tables), trait_ref.stable(tables)) + } + mir::interpret::GlobalAlloc::Static(def) => { + GlobalAlloc::Static(tables.static_def(*def)) + } + mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)), + } + } +} + impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { type T = stable_mir::ty::TraitSpecializationKind; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { @@ -1989,6 +2029,14 @@ impl<'tcx> Stable<'tcx> for MonoItem<'tcx> { } } +impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled { + type T = Error; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + Error::new(format!("{self:?}")) + } +} + impl<'tcx, T> Stable<'tcx> for &T where T: Stable<'tcx>, @@ -2010,3 +2058,18 @@ where self.as_ref().map(|value| value.stable(tables)) } } + +impl<'tcx, T, E> Stable<'tcx> for Result +where + T: Stable<'tcx>, + E: Stable<'tcx>, +{ + type T = Result; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + Ok(val) => Ok(val.stable(tables)), + Err(error) => Err(error.stable(tables)), + } + } +} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 5eb6a8a5e543e..d5c4881c89d26 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -17,7 +17,7 @@ //! The goal is to eventually be published on //! [crates.io](https://crates.io). -use crate::mir::mono::InstanceDef; +use crate::mir::mono::{InstanceDef, StaticDef}; use crate::mir::Body; use std::fmt; use std::fmt::Debug; @@ -37,9 +37,10 @@ pub mod mir; pub mod ty; pub mod visitor; +use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::pretty::function_name; use crate::mir::Mutability; -use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind, Const, RigidTy}; +use crate::ty::{AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, RigidTy}; pub use error::*; use mir::mono::Instance; use ty::{FnDef, GenericArgs}; @@ -73,19 +74,6 @@ impl IndexedVal for DefId { } } -/// A unique identification number for each provenance -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct AllocId(usize); - -impl IndexedVal for AllocId { - fn to_val(index: usize) -> Self { - AllocId(index) - } - fn to_index(&self) -> usize { - self.0 - } -} - /// A list of crate items. pub type CrateItems = Vec; @@ -141,6 +129,10 @@ impl CrateItem { with(|cx| cx.def_ty(self.0)) } + pub fn is_foreign_item(&self) -> bool { + with(|cx| cx.is_foreign_item(*self)) + } + pub fn dump(&self, w: &mut W) -> io::Result<()> { writeln!(w, "{}", function_name(*self))?; self.body().dump(w) @@ -190,6 +182,8 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait { with(|cx| cx.trait_impl(trait_impl)) } +/// This trait defines the interface between stable_mir and the Rust compiler. +/// Do not use this directly. pub trait Context { fn entry_fn(&self) -> Option; /// Retrieve all items of the local crate that have a MIR associated with them. @@ -291,6 +285,12 @@ pub trait Context { args: &GenericArgs, kind: ClosureKind, ) -> Option; + + /// Evaluate a static's initializer. + fn eval_static_initializer(&self, def: StaticDef) -> Result; + + /// Retrieve global allocation for the given allocation ID. + fn global_alloc(&self, id: AllocId) -> GlobalAlloc; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs index 2cbe6eb4ad117..82555461d644e 100644 --- a/compiler/stable_mir/src/mir.rs +++ b/compiler/stable_mir/src/mir.rs @@ -1,3 +1,4 @@ +pub mod alloc; mod body; pub mod mono; pub mod pretty; diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs new file mode 100644 index 0000000000000..ca24653585cec --- /dev/null +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -0,0 +1,37 @@ +use crate::mir::mono::{Instance, StaticDef}; +use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty}; +use crate::with; + +/// An allocation in the SMIR global memory can be either a function pointer, +/// a static, or a "real" allocation with some data in it. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum GlobalAlloc { + /// The alloc ID is used as a function pointer. + Function(Instance), + /// This alloc ID points to a symbolic (not-reified) vtable. + VTable(Ty, Option>), + /// The alloc ID points to a "lazy" static variable that did not get computed (yet). + /// This is also used to break the cycle in recursive statics. + Static(StaticDef), + /// The alloc ID points to memory. + Memory(Allocation), +} + +impl From for GlobalAlloc { + fn from(value: AllocId) -> Self { + with(|cx| cx.global_alloc(value)) + } +} + +/// A unique identification number for each provenance +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct AllocId(usize); + +impl IndexedVal for AllocId { + fn to_val(index: usize) -> Self { + AllocId(index) + } + fn to_index(&self) -> usize { + self.0 + } +} diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 8c43f2c4b8f22..9cec963cf849c 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::mir::Body; -use crate::ty::{ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; +use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque}; use std::fmt::{Debug, Formatter}; @@ -37,6 +37,11 @@ impl Instance { with(|context| context.instance_body(self.def)) } + pub fn is_foreign_item(&self) -> bool { + let item = CrateItem::try_from(*self); + item.as_ref().map_or(false, CrateItem::is_foreign_item) + } + /// Get the instance type with generic substitutions applied and lifetimes erased. pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) @@ -128,6 +133,18 @@ impl From for MonoItem { } } +impl From for MonoItem { + fn from(value: StaticDef) -> Self { + MonoItem::Static(value) + } +} + +impl From for CrateItem { + fn from(value: StaticDef) -> Self { + CrateItem(value.0) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct InstanceDef(usize); @@ -147,9 +164,15 @@ impl TryFrom for StaticDef { } impl StaticDef { + /// Return the type of this static definition. pub fn ty(&self) -> Ty { with(|cx| cx.def_ty(self.0)) } + + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. + pub fn eval_initializer(&self) -> Result { + with(|cx| cx.eval_static_initializer(*self)) + } } impl IndexedVal for InstanceDef { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index abe6f8ec12f17..010e2e7e4a69e 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1,8 +1,9 @@ use super::{ mir::Safety, mir::{Body, Mutability}, - with, AllocId, DefId, Error, Symbol, + with, DefId, Error, Symbol, }; +use crate::mir::alloc::AllocId; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter}; From 5b3cf6610b7c94d5eea715386946ba0bf564690e Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 17 Nov 2023 08:05:40 -0800 Subject: [PATCH 09/11] Add support to get virtual table allocation --- .../rustc_smir/src/rustc_internal/internal.rs | 26 +++++++++++++++++-- compiler/rustc_smir/src/rustc_internal/mod.rs | 2 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 19 ++++++++++++++ compiler/stable_mir/src/lib.rs | 3 +++ compiler/stable_mir/src/mir/alloc.rs | 7 +++++ 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 988d1d7226a18..fe226ef60ed48 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -10,8 +10,9 @@ use rustc_span::Symbol; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::ty::{ - AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, FloatTy, - GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, Ty, UintTy, + AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, + ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, + Ty, UintTy, }; use stable_mir::{CrateItem, DefId}; @@ -229,6 +230,17 @@ impl<'tcx> RustcInternal<'tcx> for BoundVariableKind { } } +impl<'tcx> RustcInternal<'tcx> for ExistentialTraitRef { + type T = rustc_ty::ExistentialTraitRef<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + rustc_ty::ExistentialTraitRef { + def_id: self.def_id.0.internal(tables), + args: self.generic_args.internal(tables), + } + } +} + impl<'tcx> RustcInternal<'tcx> for TraitRef { type T = rustc_ty::TraitRef<'tcx>; @@ -277,3 +289,13 @@ where (*self).internal(tables) } } +impl<'tcx, T> RustcInternal<'tcx> for Option +where + T: RustcInternal<'tcx>, +{ + type T = Option; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.as_ref().map(|inner| inner.internal(tables)) + } +} diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index b37c9a1f632e2..fed21f16a4e58 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -118,7 +118,7 @@ impl<'tcx> Tables<'tcx> { self.def_ids.create_or_fetch(did) } - fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::mir::alloc::AllocId { + pub(crate) fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::mir::alloc::AllocId { self.alloc_ids.create_or_fetch(aid) } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 509706387db67..403c7703debcb 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -331,6 +331,18 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.global_alloc(alloc_id).stable(&mut *tables) } + fn vtable_allocation( + &self, + global_alloc: &GlobalAlloc, + ) -> Option { + let mut tables = self.0.borrow_mut(); + let GlobalAlloc::VTable(ty, trait_ref) = global_alloc else { return None }; + let alloc_id = tables + .tcx + .vtable_allocation((ty.internal(&mut *tables), trait_ref.internal(&mut *tables))); + Some(alloc_id.stable(&mut *tables)) + } + fn usize_to_const(&self, val: u64) -> Result { let mut tables = self.0.borrow_mut(); let ty = tables.tcx.types.usize; @@ -1623,6 +1635,13 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { } } +impl<'tcx> Stable<'tcx> for mir::interpret::AllocId { + type T = stable_mir::mir::alloc::AllocId; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.create_alloc_id(*self) + } +} + impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { type T = GlobalAlloc; diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index d5c4881c89d26..6c1b723a8daea 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -291,6 +291,9 @@ pub trait Context { /// Retrieve global allocation for the given allocation ID. fn global_alloc(&self, id: AllocId) -> GlobalAlloc; + + /// Retrieve the id for the virtual table. + fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index ca24653585cec..ef9053b78ec1a 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -9,6 +9,7 @@ pub enum GlobalAlloc { /// The alloc ID is used as a function pointer. Function(Instance), /// This alloc ID points to a symbolic (not-reified) vtable. + /// The `None` trait ref is used to represent auto traits. VTable(Ty, Option>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). /// This is also used to break the cycle in recursive statics. @@ -23,6 +24,12 @@ impl From for GlobalAlloc { } } +impl GlobalAlloc { + pub fn vtable_allocation(&self) -> Option { + with(|cx| cx.vtable_allocation(self)) + } +} + /// A unique identification number for each provenance #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct AllocId(usize); From c07a6d5c9a1aa748d2b7493dbeb4374761919876 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Mon, 20 Nov 2023 11:39:04 -0800 Subject: [PATCH 10/11] Add allocation test and a bit more documentation --- compiler/stable_mir/src/mir/alloc.rs | 7 ++ .../stable-mir/check_allocation.rs | 119 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 tests/ui-fulldeps/stable-mir/check_allocation.rs diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index ef9053b78ec1a..af951bcef8c1e 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -1,3 +1,4 @@ +//! This module provides methods to retrieve allocation information, such as static variables. use crate::mir::mono::{Instance, StaticDef}; use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty}; use crate::with; @@ -25,6 +26,12 @@ impl From for GlobalAlloc { } impl GlobalAlloc { + /// Retrieve the allocation id for a global allocation if it exists. + /// + /// For `[GlobalAlloc::VTable]`, this will return the allocation for the VTable of the given + /// type for the optional trait if the type implements the trait. + /// + /// This method will always return `None` for allocations other than `[GlobalAlloc::VTable]`. pub fn vtable_allocation(&self) -> Option { with(|cx| cx.vtable_allocation(self)) } diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs new file mode 100644 index 0000000000000..e5fb7311c0b84 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -0,0 +1,119 @@ +// run-pass +//! Test that users are able to use stable mir APIs to retrieve information of global allocations +//! such as `vtable_allocation`. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] +#![feature(ascii_char, ascii_char_variants)] + +extern crate rustc_hir; +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::{CrateItem, CrateItems, ItemKind}; +use stable_mir::mir::alloc::GlobalAlloc; +use stable_mir::mir::mono::StaticDef; +use std::ascii::Char; +use std::assert_matches::assert_matches; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + // Find items in the local crate. + let items = stable_mir::all_local_items(); + check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap()); + check_bar(*get_item(&items, (ItemKind::Static, "BAR")).unwrap()); + ControlFlow::Continue(()) +} + +/// Check the allocation data for static `FOO`. +/// +/// ```no_run +/// static FOO: [&str; 2] = ["hi", "there"]; +/// ``` +fn check_foo(item: CrateItem) { + let def = StaticDef::try_from(item).unwrap(); + let alloc = def.eval_initializer().unwrap(); + assert_eq!(alloc.provenance.ptrs.len(), 2); + + let alloc_id_0 = alloc.provenance.ptrs[0].1.0; + assert_matches!(GlobalAlloc::from(alloc_id_0), GlobalAlloc::Memory(..)); + + let alloc_id_1 = alloc.provenance.ptrs[1].1.0; + assert_matches!(GlobalAlloc::from(alloc_id_1), GlobalAlloc::Memory(..)); +} + +/// Check the allocation data for static `BAR`. +/// +/// ```no_run +/// static BAR: &str = "Bar"; +/// ``` +fn check_bar(item: CrateItem) { + let def = StaticDef::try_from(item).unwrap(); + let alloc = def.eval_initializer().unwrap(); + assert_eq!(alloc.provenance.ptrs.len(), 1); + + let alloc_id_0 = alloc.provenance.ptrs[0].1.0; + let GlobalAlloc::Memory(allocation) = GlobalAlloc::from(alloc_id_0) else { unreachable!() }; + assert_eq!(allocation.bytes.len(), 3); + assert_eq!(allocation.bytes[0].unwrap(), Char::CapitalB.to_u8()); + assert_eq!(allocation.bytes[1].unwrap(), Char::SmallA.to_u8()); + assert_eq!(allocation.bytes[2].unwrap(), Char::SmallR.to_u8()); +} + +// Use internal API to find a function in a crate. +fn get_item<'a>( + items: &'a CrateItems, + item: (ItemKind, &str), +) -> Option<&'a stable_mir::CrateItem> { + items.iter().find(|crate_item| { + (item.0 == crate_item.kind()) && crate_item.name() == item.1 + }) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "alloc_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_stable_mir(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + static FOO: [&str; 2] = ["hi", "there"]; + static BAR: &str = "Bar"; + + pub fn main() {{ + println!("{{FOO:?}}! {{BAR}}"); + }}"# + )?; + Ok(()) +} From 4f958a4802c1c29b804db34d53297504da555d02 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 22 Nov 2023 03:43:59 +0000 Subject: [PATCH 11/11] Allow defining opaques in check_coroutine_obligations --- .../rustc_hir_analysis/src/check/check.rs | 22 +++++++++++++++---- compiler/rustc_middle/src/query/mod.rs | 2 +- tests/ui/coroutine/clone-rpit.rs | 17 ++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 tests/ui/coroutine/clone-rpit.rs diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e301f0b22ef77..00f636862beb2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1468,7 +1468,10 @@ fn opaque_type_cycle_error( err.emit() } -pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { +pub(super) fn check_coroutine_obligations( + tcx: TyCtxt<'_>, + def_id: LocalDefId, +) -> Result<(), ErrorGuaranteed> { debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Coroutine)); let typeck = tcx.typeck(def_id); @@ -1482,8 +1485,9 @@ pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { // typeck writeback gives us predicates with their regions erased. // As borrowck already has checked lifetimes, we do not need to do it again. .ignoring_regions() - // Bind opaque types to `def_id` as they should have been checked by borrowck. - .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) + // Bind opaque types to type checking root, as they should have been checked by borrowck, + // but may show up in some cases, like when (root) obligations are stalled in the new solver. + .with_opaque_type_inference(DefiningAnchor::Bind(typeck.hir_owner.def_id)) .build(); let mut fulfillment_cx = >::new(&infcx); @@ -1513,6 +1517,16 @@ pub(super) fn check_coroutine_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { let errors = fulfillment_cx.select_all_or_error(&infcx); debug!(?errors); if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } + + // Check that any hidden types found when checking these stalled coroutine obligations + // are valid. + for (key, ty) in infcx.take_opaque_types() { + let hidden_type = infcx.resolve_vars_if_possible(ty.hidden_type); + let key = infcx.resolve_vars_if_possible(key); + sanity_check_found_hidden_type(tcx, key, hidden_type)?; + } + + Ok(()) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cbba990867e03..c982e2a93253f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -567,7 +567,7 @@ rustc_queries! { separate_provide_extern } - query check_coroutine_obligations(key: LocalDefId) { + query check_coroutine_obligations(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "verify auto trait bounds for coroutine interior type `{}`", tcx.def_path_str(key) } } diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs new file mode 100644 index 0000000000000..e0061e1c6bb33 --- /dev/null +++ b/tests/ui/coroutine/clone-rpit.rs @@ -0,0 +1,17 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(coroutines, coroutine_trait, coroutine_clone)] + +// This stalls the goal `{coroutine} <: impl Clone`, since that has a nested goal +// of `{coroutine}: Clone`. That is only known if we can compute the generator +// witness types, which we don't know until after borrowck. When we later check +// the goal for correctness, we want to be able to bind the `impl Clone` opaque. +pub fn foo<'a, 'b>() -> impl Clone { + move |_: ()| { + let () = yield (); + } +} + +fn main() {}