Skip to content

Commit d541876

Browse files
committedOct 20, 2018
Auto merge of #55230 - Manishearth:rollup, r=Manishearth
Rollup of 5 pull requests Successful merges: - #55156 (Fixed: Multiple errors on single typo in match pattern) - #55189 (update books for the next release) - #55193 (make asm diagnostic instruction optional) - #55203 (Write an initial version of the `program_clauses` callback) - #55213 (ignore target folders) Failed merges: r? @ghost
2 parents 155510e + f2848a0 commit d541876

File tree

17 files changed

+551
-38
lines changed

17 files changed

+551
-38
lines changed
 

‎src/doc/nomicon

‎src/doc/reference

‎src/librustc_codegen_llvm/back/lto.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ impl LtoModuleCodegen {
8080
let module = module.take().unwrap();
8181
{
8282
let config = cgcx.config(module.kind);
83-
let llmod = module.module_llvm.llmod();
84-
let tm = &*module.module_llvm.tm;
85-
run_pass_manager(cgcx, tm, llmod, config, false);
83+
run_pass_manager(cgcx, &module, config, false);
8684
timeline.record("fat-done");
8785
}
8886
Ok(module)
@@ -557,8 +555,7 @@ fn thin_lto(cgcx: &CodegenContext,
557555
}
558556

559557
fn run_pass_manager(cgcx: &CodegenContext,
560-
tm: &llvm::TargetMachine,
561-
llmod: &llvm::Module,
558+
module: &ModuleCodegen,
562559
config: &ModuleConfig,
563560
thin: bool) {
564561
// Now we have one massive module inside of llmod. Time to run the
@@ -569,7 +566,8 @@ fn run_pass_manager(cgcx: &CodegenContext,
569566
debug!("running the pass manager");
570567
unsafe {
571568
let pm = llvm::LLVMCreatePassManager();
572-
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
569+
let llmod = module.module_llvm.llmod();
570+
llvm::LLVMRustAddAnalysisPasses(module.module_llvm.tm, pm, llmod);
573571

574572
if config.verify_llvm_ir {
575573
let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
@@ -864,7 +862,7 @@ impl ThinModule {
864862
// little differently.
865863
info!("running thin lto passes over {}", module.name);
866864
let config = cgcx.config(module.kind);
867-
run_pass_manager(cgcx, module.module_llvm.tm, llmod, config, true);
865+
run_pass_manager(cgcx, &module, config, true);
868866
cgcx.save_temp_bitcode(&module, "thin-lto-after-pm");
869867
timeline.record("thin-done");
870868
}

‎src/librustc_codegen_llvm/back/write.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
633633
None,
634634
&format!("llvm module passes [{}]", module_name.unwrap()),
635635
|| {
636-
llvm::LLVMRunPassManager(mpm, llmod)
636+
llvm::LLVMRunPassManager(mpm, llmod);
637637
});
638638

639639
// Deallocate managers that we're now done with
@@ -691,6 +691,38 @@ unsafe fn codegen(cgcx: &CodegenContext,
691691
create_msvc_imps(cgcx, llcx, llmod);
692692
}
693693

694+
// Ok now this one's a super interesting invocations. SIMD in rustc is
695+
// difficult where we want some parts of the program to be able to use
696+
// some SIMD features while other parts of the program don't. The real
697+
// tough part is that we want this to actually work correctly!
698+
//
699+
// We go to great lengths to make sure this works, and one crucial
700+
// aspect is that vector arguments (simd types) are never passed by
701+
// value in the ABI of functions. It turns out, however, that LLVM will
702+
// undo our "clever work" of passing vector types by reference. Its
703+
// argument promotion pass will promote these by-ref arguments to
704+
// by-val. That, however, introduces codegen errors!
705+
//
706+
// The upstream LLVM bug [1] has unfortunatey not really seen a lot of
707+
// activity. The Rust bug [2], however, has seen quite a lot of reports
708+
// of this in the wild. As a result, this is worked around locally here.
709+
// We have a custom transformation, `LLVMRustDemoteSimdArguments`, which
710+
// does the opposite of argument promotion by demoting any by-value SIMD
711+
// arguments in function signatures to pointers intead of being
712+
// by-value.
713+
//
714+
// This operates at the LLVM IR layer because LLVM is thwarting our
715+
// codegen and this is the only chance we get to make sure it's correct
716+
// before we hit codegen.
717+
//
718+
// Hopefully one day the upstream LLVM bug will be fixed and we'll no
719+
// longer need this!
720+
//
721+
// [1]: https://bugs.llvm.org/show_bug.cgi?id=37358
722+
// [2]: https://github.com/rust-lang/rust/issues/50154
723+
llvm::LLVMRustDemoteSimdArguments(llmod);
724+
cgcx.save_temp_bitcode(&module, "simd-demoted");
725+
694726
// A codegen-specific pass manager is used to generate object
695727
// files for an LLVM module.
696728
//

‎src/librustc_codegen_llvm/llvm/ffi.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,8 @@ extern "C" {
11381138
/// Runs a pass manager on a module.
11391139
pub fn LLVMRunPassManager(PM: &PassManager<'a>, M: &'a Module) -> Bool;
11401140

1141+
pub fn LLVMRustDemoteSimdArguments(M: &'a Module);
1142+
11411143
pub fn LLVMInitializePasses();
11421144

11431145
pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;

‎src/librustc_llvm/build.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ fn main() {
162162
}
163163

164164
build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm"));
165-
cfg.file("../rustllvm/PassWrapper.cpp")
165+
cfg
166+
.file("../rustllvm/DemoteSimd.cpp")
167+
.file("../rustllvm/PassWrapper.cpp")
166168
.file("../rustllvm/RustWrapper.cpp")
167169
.file("../rustllvm/ArchiveWrapper.cpp")
168170
.file("../rustllvm/Linker.cpp")

‎src/librustc_traits/chalk_context.rs

+207-21
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@ use rustc::traits::{
2323
Goal,
2424
GoalKind,
2525
Clause,
26+
ProgramClauseCategory,
2627
QuantifierKind,
2728
Environment,
2829
InEnvironment,
2930
};
3031
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
3132
use rustc::ty::subst::Kind;
3233
use rustc::ty::{self, TyCtxt};
34+
use rustc::hir::def_id::DefId;
3335

3436
use std::fmt::{self, Debug};
3537
use std::marker::PhantomData;
@@ -330,46 +332,230 @@ impl context::UnificationOps<ChalkArenas<'gcx>, ChalkArenas<'tcx>>
330332
{
331333
fn program_clauses(
332334
&self,
333-
_environment: &Environment<'tcx>,
335+
environment: &Environment<'tcx>,
334336
goal: &DomainGoal<'tcx>,
335337
) -> Vec<Clause<'tcx>> {
336338
use rustc::traits::WhereClause::*;
337339

338-
match goal {
339-
DomainGoal::Holds(Implemented(_trait_predicate)) => {
340+
fn assemble_clauses_from_impls<'tcx>(
341+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
342+
trait_def_id: DefId,
343+
clauses: &mut Vec<Clause<'tcx>>
344+
) {
345+
tcx.for_each_impl(trait_def_id, |impl_def_id| {
346+
clauses.extend(
347+
tcx.program_clauses_for(impl_def_id)
348+
.into_iter()
349+
.cloned()
350+
);
351+
});
352+
}
353+
354+
fn assemble_clauses_from_assoc_ty_values<'tcx>(
355+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
356+
trait_def_id: DefId,
357+
clauses: &mut Vec<Clause<'tcx>>
358+
) {
359+
tcx.for_each_impl(trait_def_id, |impl_def_id| {
360+
for def_id in tcx.associated_item_def_ids(impl_def_id).iter() {
361+
clauses.extend(
362+
tcx.program_clauses_for(*def_id)
363+
.into_iter()
364+
.cloned()
365+
);
366+
}
367+
});
368+
}
369+
370+
let mut clauses = match goal {
371+
DomainGoal::Holds(Implemented(trait_predicate)) => {
372+
// These come from:
373+
// * implementations of the trait itself (rule `Implemented-From-Impl`)
374+
// * the trait decl (rule `Implemented-From-Env`)
375+
376+
let mut clauses = vec![];
377+
assemble_clauses_from_impls(
378+
self.infcx.tcx,
379+
trait_predicate.def_id(),
380+
&mut clauses
381+
);
382+
383+
// FIXME: we need to add special rules for builtin impls:
384+
// * `Copy` / `Clone`
385+
// * `Sized`
386+
// * `Unsize`
387+
// * `Generator`
388+
// * `FnOnce` / `FnMut` / `Fn`
389+
// * trait objects
390+
// * auto traits
391+
392+
// Rule `Implemented-From-Env` will be computed from the environment.
393+
clauses
394+
}
395+
396+
DomainGoal::Holds(ProjectionEq(projection_predicate)) => {
397+
// These come from:
398+
// * the assoc type definition (rule `ProjectionEq-Placeholder`)
399+
// * normalization of the assoc ty values (rule `ProjectionEq-Normalize`)
400+
// * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
401+
// * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
402+
403+
let clauses = self.infcx.tcx.program_clauses_for(
404+
projection_predicate.projection_ty.item_def_id
405+
).into_iter()
406+
407+
// only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize`
408+
.filter(|clause| clause.category() == ProgramClauseCategory::Other)
409+
410+
.cloned()
411+
.collect::<Vec<_>>();
412+
413+
// Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed
414+
// from the environment.
415+
clauses
416+
}
417+
418+
DomainGoal::Holds(RegionOutlives(..)) => {
340419
// These come from:
341-
//
342-
// - Trait definitions (implied bounds)
343-
// - Implementations of the trait itself
344-
panic!()
420+
// * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
421+
// * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
422+
423+
// All of these rules are computed in the environment.
424+
vec![]
345425
}
346426

347-
DomainGoal::Holds(ProjectionEq(_projection_predicate)) => {
427+
DomainGoal::Holds(TypeOutlives(..)) => {
348428
// These come from:
349-
panic!()
429+
// * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
430+
// * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
431+
432+
// All of these rules are computed in the environment.
433+
vec![]
350434
}
351435

352-
DomainGoal::Holds(RegionOutlives(_region_outlives)) => {
353-
panic!()
436+
DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => {
437+
// These come from -- the trait decl (rule `WellFormed-TraitRef`).
438+
self.infcx.tcx.program_clauses_for(trait_predicate.def_id())
439+
.into_iter()
440+
441+
// only select `WellFormed-TraitRef`
442+
.filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
443+
444+
.cloned()
445+
.collect()
354446
}
355447

356-
DomainGoal::Holds(TypeOutlives(_type_outlives)) => {
357-
panic!()
448+
DomainGoal::WellFormed(WellFormed::Ty(ty)) => {
449+
// These come from:
450+
// * the associated type definition if `ty` refers to an unnormalized
451+
// associated type (rule `WellFormed-AssocTy`)
452+
// * custom rules for built-in types
453+
// * the type definition otherwise (rule `WellFormed-Type`)
454+
let clauses = match ty.sty {
455+
ty::Projection(data) => {
456+
self.infcx.tcx.program_clauses_for(data.item_def_id)
457+
}
458+
459+
// These types are always WF (recall that we do not check
460+
// for parameters to be WF)
461+
ty::Bool |
462+
ty::Char |
463+
ty::Int(..) |
464+
ty::Uint(..) |
465+
ty::Float(..) |
466+
ty::Str |
467+
ty::RawPtr(..) |
468+
ty::FnPtr(..) |
469+
ty::Param(..) |
470+
ty::Never => {
471+
ty::List::empty()
472+
}
473+
474+
// WF if inner type is `Sized`
475+
ty::Slice(..) |
476+
ty::Array(..) => {
477+
ty::List::empty()
478+
}
479+
480+
ty::Tuple(..) => {
481+
ty::List::empty()
482+
}
483+
484+
// WF if `sub_ty` outlives `region`
485+
ty::Ref(..) => {
486+
ty::List::empty()
487+
}
488+
489+
ty::Dynamic(..) => {
490+
// FIXME: no rules yet for trait objects
491+
ty::List::empty()
492+
}
493+
494+
ty::Adt(def, ..) => {
495+
self.infcx.tcx.program_clauses_for(def.did)
496+
}
497+
498+
ty::Foreign(def_id) |
499+
ty::FnDef(def_id, ..) |
500+
ty::Closure(def_id, ..) |
501+
ty::Generator(def_id, ..) |
502+
ty::Opaque(def_id, ..) => {
503+
self.infcx.tcx.program_clauses_for(def_id)
504+
}
505+
506+
ty::GeneratorWitness(..) |
507+
ty::UnnormalizedProjection(..) |
508+
ty::Infer(..) |
509+
ty::Error => {
510+
bug!("unexpected type {:?}", ty)
511+
}
512+
};
513+
514+
clauses.into_iter()
515+
.filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
516+
.cloned()
517+
.collect()
358518
}
359519

360-
DomainGoal::WellFormed(WellFormed::Trait(_trait_predicate)) => {
361-
// These come from -- the trait decl.
362-
panic!()
520+
DomainGoal::FromEnv(FromEnv::Trait(..)) => {
521+
// These come from:
522+
// * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
523+
// * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
524+
// * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`,
525+
// `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`)
526+
527+
// All of these rules are computed in the environment.
528+
vec![]
363529
}
364530

365-
DomainGoal::WellFormed(WellFormed::Ty(_ty)) => panic!(),
531+
DomainGoal::FromEnv(FromEnv::Ty(..)) => {
532+
// There are no `FromEnv::Ty(..) :- ...` rules (this predicate only
533+
// comes from the environment).
534+
vec![]
535+
}
366536

367-
DomainGoal::FromEnv(FromEnv::Trait(_trait_predicate)) => panic!(),
537+
DomainGoal::Normalize(projection_predicate) => {
538+
// These come from -- assoc ty values (rule `Normalize-From-Impl`).
539+
let mut clauses = vec![];
368540

369-
DomainGoal::FromEnv(FromEnv::Ty(_ty)) => panic!(),
541+
assemble_clauses_from_assoc_ty_values(
542+
self.infcx.tcx,
543+
projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id,
544+
&mut clauses
545+
);
370546

371-
DomainGoal::Normalize(_) => panic!(),
372-
}
547+
clauses
548+
}
549+
};
550+
551+
let environment = self.infcx.tcx.lift_to_global(environment)
552+
.expect("environment is not global");
553+
clauses.extend(
554+
self.infcx.tcx.program_clauses_for_env(environment)
555+
.into_iter()
556+
.cloned()
557+
);
558+
clauses
373559
}
374560

375561
fn instantiate_binders_universally(

‎src/librustc_traits/lowering/environment.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,16 @@ impl ClauseVisitor<'set, 'a, 'tcx> {
8686
ty::Slice(..) |
8787
ty::RawPtr(..) |
8888
ty::FnPtr(..) |
89-
ty::Never |
9089
ty::Tuple(..) |
90+
ty::Never |
91+
ty::Param(..) => (),
92+
9193
ty::GeneratorWitness(..) |
9294
ty::UnnormalizedProjection(..) |
93-
ty::Param(..) |
9495
ty::Infer(..) |
95-
ty::Error => (),
96+
ty::Error => {
97+
bug!("unexpected type {:?}", ty);
98+
}
9699
}
97100
}
98101

‎src/librustc_traits/lowering/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>(
433433
let wf_clause = ProgramClause {
434434
goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
435435
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
436-
category: ProgramClauseCategory::Other,
436+
category: ProgramClauseCategory::WellFormed,
437437
};
438438

439439
// Rule Implied-Trait-From-AssocTy

‎src/rustllvm/DemoteSimd.cpp

+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#include <vector>
12+
#include <set>
13+
14+
#include "rustllvm.h"
15+
16+
#if LLVM_VERSION_GE(5, 0)
17+
18+
#include "llvm/IR/CallSite.h"
19+
#include "llvm/IR/Module.h"
20+
#include "llvm/ADT/STLExtras.h"
21+
22+
using namespace llvm;
23+
24+
static std::vector<Function*>
25+
GetFunctionsWithSimdArgs(Module *M) {
26+
std::vector<Function*> Ret;
27+
28+
for (auto &F : M->functions()) {
29+
// Skip all intrinsic calls as these are always tightly controlled to "work
30+
// correctly", so no need to fixup any of these.
31+
if (F.isIntrinsic())
32+
continue;
33+
34+
// We're only interested in rustc-defined functions, not unstably-defined
35+
// imported SIMD ffi functions.
36+
if (F.isDeclaration())
37+
continue;
38+
39+
// Argument promotion only happens on internal functions, so skip demoting
40+
// arguments in external functions like FFI shims and such.
41+
if (!F.hasLocalLinkage())
42+
continue;
43+
44+
// If any argument to this function is a by-value vector type, then that's
45+
// bad! The compiler didn't generate any functions that looked like this,
46+
// and we try to rely on LLVM to not do this! Argument promotion may,
47+
// however, promote arguments from behind references. In any case, figure
48+
// out if we're interested in demoting this argument.
49+
if (any_of(F.args(), [](Argument &arg) { return arg.getType()->isVectorTy(); }))
50+
Ret.push_back(&F);
51+
}
52+
53+
return Ret;
54+
}
55+
56+
extern "C" void
57+
LLVMRustDemoteSimdArguments(LLVMModuleRef Mod) {
58+
Module *M = unwrap(Mod);
59+
60+
auto Functions = GetFunctionsWithSimdArgs(M);
61+
62+
for (auto F : Functions) {
63+
// Build up our list of new parameters and new argument attributes.
64+
// We're only changing those arguments which are vector types.
65+
SmallVector<Type*, 8> Params;
66+
SmallVector<AttributeSet, 8> ArgAttrVec;
67+
auto PAL = F->getAttributes();
68+
for (auto &Arg : F->args()) {
69+
auto *Ty = Arg.getType();
70+
if (Ty->isVectorTy()) {
71+
Params.push_back(PointerType::get(Ty, 0));
72+
ArgAttrVec.push_back(AttributeSet());
73+
} else {
74+
Params.push_back(Ty);
75+
ArgAttrVec.push_back(PAL.getParamAttributes(Arg.getArgNo()));
76+
}
77+
}
78+
79+
// Replace `F` with a new function with our new signature. I'm... not really
80+
// sure how this works, but this is all the steps `ArgumentPromotion` does
81+
// to replace a signature as well.
82+
assert(!F->isVarArg()); // ArgumentPromotion should skip these fns
83+
FunctionType *NFTy = FunctionType::get(F->getReturnType(), Params, false);
84+
Function *NF = Function::Create(NFTy, F->getLinkage(), F->getName());
85+
NF->copyAttributesFrom(F);
86+
NF->setSubprogram(F->getSubprogram());
87+
F->setSubprogram(nullptr);
88+
NF->setAttributes(AttributeList::get(F->getContext(),
89+
PAL.getFnAttributes(),
90+
PAL.getRetAttributes(),
91+
ArgAttrVec));
92+
ArgAttrVec.clear();
93+
F->getParent()->getFunctionList().insert(F->getIterator(), NF);
94+
NF->takeName(F);
95+
96+
// Iterate over all invocations of `F`, updating all `call` instructions to
97+
// store immediate vector types in a local `alloc` instead of a by-value
98+
// vector.
99+
//
100+
// Like before, much of this is copied from the `ArgumentPromotion` pass in
101+
// LLVM.
102+
SmallVector<Value*, 16> Args;
103+
while (!F->use_empty()) {
104+
CallSite CS(F->user_back());
105+
assert(CS.getCalledFunction() == F);
106+
Instruction *Call = CS.getInstruction();
107+
const AttributeList &CallPAL = CS.getAttributes();
108+
109+
// Loop over the operands, inserting an `alloca` and a store for any
110+
// argument we're demoting to be by reference
111+
//
112+
// FIXME: we probably want to figure out an LLVM pass to run and clean up
113+
// this function and instructions we're generating, we should in theory
114+
// only generate a maximum number of `alloca` instructions rather than
115+
// one-per-variable unconditionally.
116+
CallSite::arg_iterator AI = CS.arg_begin();
117+
size_t ArgNo = 0;
118+
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
119+
++I, ++AI, ++ArgNo) {
120+
if (I->getType()->isVectorTy()) {
121+
AllocaInst *AllocA = new AllocaInst(I->getType(), 0, nullptr, "", Call);
122+
new StoreInst(*AI, AllocA, Call);
123+
Args.push_back(AllocA);
124+
ArgAttrVec.push_back(AttributeSet());
125+
} else {
126+
Args.push_back(*AI);
127+
ArgAttrVec.push_back(CallPAL.getParamAttributes(ArgNo));
128+
}
129+
}
130+
assert(AI == CS.arg_end());
131+
132+
// Create a new call instructions which we'll use to replace the old call
133+
// instruction, copying over as many attributes and such as possible.
134+
SmallVector<OperandBundleDef, 1> OpBundles;
135+
CS.getOperandBundlesAsDefs(OpBundles);
136+
137+
CallSite NewCS;
138+
if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
139+
InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(),
140+
Args, OpBundles, "", Call);
141+
} else {
142+
auto *NewCall = CallInst::Create(NF, Args, OpBundles, "", Call);
143+
NewCall->setTailCallKind(cast<CallInst>(Call)->getTailCallKind());
144+
NewCS = NewCall;
145+
}
146+
NewCS.setCallingConv(CS.getCallingConv());
147+
NewCS.setAttributes(
148+
AttributeList::get(F->getContext(), CallPAL.getFnAttributes(),
149+
CallPAL.getRetAttributes(), ArgAttrVec));
150+
NewCS->setDebugLoc(Call->getDebugLoc());
151+
Args.clear();
152+
ArgAttrVec.clear();
153+
Call->replaceAllUsesWith(NewCS.getInstruction());
154+
NewCS->takeName(Call);
155+
Call->eraseFromParent();
156+
}
157+
158+
// Splice the body of the old function right into the new function.
159+
NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList());
160+
161+
// Update our new function to replace all uses of the by-value argument with
162+
// loads of the pointer argument we've generated.
163+
//
164+
// FIXME: we probably want to only generate one load instruction per
165+
// function? Or maybe run an LLVM pass to clean up this function?
166+
for (Function::arg_iterator I = F->arg_begin(),
167+
E = F->arg_end(),
168+
I2 = NF->arg_begin();
169+
I != E;
170+
++I, ++I2) {
171+
if (I->getType()->isVectorTy()) {
172+
I->replaceAllUsesWith(new LoadInst(&*I2, "", &NF->begin()->front()));
173+
} else {
174+
I->replaceAllUsesWith(&*I2);
175+
}
176+
I2->takeName(&*I);
177+
}
178+
179+
// Delete all references to the old function, it should be entirely dead
180+
// now.
181+
M->getFunctionList().remove(F);
182+
}
183+
}
184+
185+
#else // LLVM_VERSION_GE(8, 0)
186+
extern "C" void
187+
LLVMRustDemoteSimdArguments(LLVMModuleRef Mod) {
188+
}
189+
#endif // LLVM_VERSION_GE(8, 0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-include ../../run-make-fulldeps/tools.mk
2+
3+
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
4+
all:
5+
$(RUSTC) t1.rs -C opt-level=3
6+
$(TMPDIR)/t1
7+
$(RUSTC) t2.rs -C opt-level=3
8+
$(TMPDIR)/t2
9+
$(RUSTC) t3.rs -C opt-level=3
10+
$(TMPDIR)/t3
11+
else
12+
all:
13+
endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::arch::x86_64;
2+
3+
fn main() {
4+
if !is_x86_feature_detected!("avx2") {
5+
return println!("AVX2 is not supported on this machine/build.");
6+
}
7+
let load_bytes: [u8; 32] = [0x0f; 32];
8+
let lb_ptr = load_bytes.as_ptr();
9+
let reg_load = unsafe {
10+
x86_64::_mm256_loadu_si256(
11+
lb_ptr as *const x86_64::__m256i
12+
)
13+
};
14+
println!("{:?}", reg_load);
15+
let mut store_bytes: [u8; 32] = [0; 32];
16+
let sb_ptr = store_bytes.as_mut_ptr();
17+
unsafe {
18+
x86_64::_mm256_storeu_si256(sb_ptr as *mut x86_64::__m256i, reg_load);
19+
}
20+
assert_eq!(load_bytes, store_bytes);
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use std::arch::x86_64::*;
2+
3+
fn main() {
4+
if !is_x86_feature_detected!("avx") {
5+
return println!("AVX is not supported on this machine/build.");
6+
}
7+
unsafe {
8+
let f = _mm256_set_pd(2.0, 2.0, 2.0, 2.0);
9+
let r = _mm256_mul_pd(f, f);
10+
11+
union A { a: __m256d, b: [f64; 4] }
12+
assert_eq!(A { a: r }.b, [4.0, 4.0, 4.0, 4.0]);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use std::arch::x86_64::*;
2+
3+
#[target_feature(enable = "avx")]
4+
unsafe fn avx_mul(a: __m256, b: __m256) -> __m256 {
5+
_mm256_mul_ps(a, b)
6+
}
7+
8+
#[target_feature(enable = "avx")]
9+
unsafe fn avx_store(p: *mut f32, a: __m256) {
10+
_mm256_storeu_ps(p, a)
11+
}
12+
13+
#[target_feature(enable = "avx")]
14+
unsafe fn avx_setr(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> __m256 {
15+
_mm256_setr_ps(a, b, c, d, e, f, g, h)
16+
}
17+
18+
#[target_feature(enable = "avx")]
19+
unsafe fn avx_set1(a: f32) -> __m256 {
20+
_mm256_set1_ps(a)
21+
}
22+
23+
struct Avx(__m256);
24+
25+
fn mul(a: Avx, b: Avx) -> Avx {
26+
unsafe { Avx(avx_mul(a.0, b.0)) }
27+
}
28+
29+
fn set1(a: f32) -> Avx {
30+
unsafe { Avx(avx_set1(a)) }
31+
}
32+
33+
fn setr(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32, g: f32, h: f32) -> Avx {
34+
unsafe { Avx(avx_setr(a, b, c, d, e, f, g, h)) }
35+
}
36+
37+
unsafe fn store(p: *mut f32, a: Avx) {
38+
avx_store(p, a.0);
39+
}
40+
41+
fn main() {
42+
if !is_x86_feature_detected!("avx") {
43+
return println!("AVX is not supported on this machine/build.");
44+
}
45+
let mut result = [0.0f32; 8];
46+
let a = mul(setr(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0), set1(0.25));
47+
unsafe {
48+
store(result.as_mut_ptr(), a);
49+
}
50+
51+
assert_eq!(result, [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.50, 1.75]);
52+
}

‎src/tools/tidy/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ fn filter_dirs(path: &Path) -> bool {
7878
"src/tools/lldb",
7979
"src/target",
8080
"src/stdsimd",
81+
"target",
8182
];
8283
skip.iter().any(|p| path.ends_with(p))
8384
}

0 commit comments

Comments
 (0)
Please sign in to comment.