erichkeane updated this revision to Diff 127005.
erichkeane added a comment.

Fix error message per @aaron.ballman s suggestion.


https://reviews.llvm.org/D40819

Files:
  include/clang/AST/Decl.h
  include/clang/Basic/Attr.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/TargetInfo.h
  include/clang/Basic/X86Target.def
  include/clang/Sema/Overload.h
  lib/Basic/Targets/X86.cpp
  lib/Basic/Targets/X86.h
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenModule.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaOverload.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CodeGen/attr-target-mv-func-ptrs.c
  test/CodeGen/attr-target-mv-va-args.c
  test/CodeGen/attr-target-mv.c
  test/CodeGenCXX/attr-target-mv-constexpr.cpp
  test/CodeGenCXX/attr-target-mv-diff-ns.cpp
  test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
  test/CodeGenCXX/attr-target-mv-member-funcs.cpp
  test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
  test/CodeGenCXX/attr-target-mv-overloads.cpp
  test/Sema/attr-target-mv-bad-target.c
  test/Sema/attr-target-mv.c
  test/SemaCXX/attr-target-mv.cpp

Index: test/SemaCXX/attr-target-mv.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/attr-target-mv.cpp
@@ -0,0 +1,131 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu  -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++14
+void __attribute__((target("sse4.2"))) no_default(void);
+void __attribute__((target("arch=sandybridge")))  no_default(void);
+
+void use1(void){
+  // expected-note@-4 {{candidate ignored: non-default multiversion function cannot be called directly}}
+  // expected-note@-4 {{candidate ignored: non-default multiversion function cannot be called directly}}
+  // expected-error@+1 {{no matching function for call to 'no_default'}}
+  no_default();
+}
+constexpr int __attribute__((target("sse4.2"))) foo(void) { return 0; }
+constexpr int __attribute__((target("arch=sandybridge"))) foo(void);
+//expected-error@+1 {{multiversion function declaration has a different constexpr specification}}
+int __attribute__((target("arch=ivybridge"))) foo(void) {return 1;}
+constexpr int __attribute__((target("default"))) foo(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) foo2(void) { return 0; }
+//expected-error@+2 {{multiversion function declaration has a different constexpr specification}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+constexpr int __attribute__((target("arch=sandybridge"))) foo2(void);
+int __attribute__((target("arch=ivybridge"))) foo2(void) {return 1;}
+int __attribute__((target("default"))) foo2(void) { return 2; }
+
+static int __attribute__((target("sse4.2"))) bar(void) { return 0; }
+static int __attribute__((target("arch=sandybridge"))) bar(void);
+//expected-error@+1 {{multiversion function declaration has a different storage class}}
+int __attribute__((target("arch=ivybridge"))) bar(void) {return 1;}
+static int __attribute__((target("default"))) bar(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) bar2(void) { return 0; }
+//expected-error@+2 {{multiversion function declaration has a different storage class}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+static int __attribute__((target("arch=sandybridge"))) bar2(void);
+int __attribute__((target("arch=ivybridge"))) bar2(void) {return 1;}
+int __attribute__((target("default"))) bar2(void) { return 2; }
+
+
+inline int __attribute__((target("sse4.2"))) baz(void) { return 0; }
+inline int __attribute__((target("arch=sandybridge"))) baz(void);
+//expected-error@+1 {{multiversion function declaration has a different inline specification}}
+int __attribute__((target("arch=ivybridge"))) baz(void) {return 1;}
+inline int __attribute__((target("default"))) baz(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) baz2(void) { return 0; }
+//expected-error@+2 {{multiversion function declaration has a different inline specification}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+inline int __attribute__((target("arch=sandybridge"))) baz2(void);
+int __attribute__((target("arch=ivybridge"))) baz2(void) {return 1;}
+int __attribute__((target("default"))) baz2(void) { return 2; }
+
+float __attribute__((target("sse4.2"))) bock(void) { return 0; }
+//expected-error@+2 {{multiversion function declaration has a different return type}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("arch=sandybridge"))) bock(void);
+//expected-error@+2 {{multiversion function declaration has a different return type}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("arch=ivybridge"))) bock(void) {return 1;}
+//expected-error@+2 {{multiversion function declaration has a different return type}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("default"))) bock(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) bock2(void) { return 0; }
+//expected-error@+2 {{multiversion function declaration has a different return type}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+float __attribute__((target("arch=sandybridge"))) bock2(void);
+int __attribute__((target("arch=ivybridge"))) bock2(void) {return 1;}
+int __attribute__((target("default"))) bock2(void) { return 2; }
+
+auto __attribute__((target("sse4.2"))) bock3(void) -> int { return 0; }
+//expected-error@+2 {{multiversion function declaration has a different return type}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+auto __attribute__((target("arch=sandybridge"))) bock3(void) -> short { return (short)0;}
+
+int __attribute__((target("sse4.2"))) bock4(void) noexcept(false) { return 0; }
+//expected-error@+2 {{exception specification in declaration does not match previous declaration}}
+//expected-note@-2 {{previous declaration is here}}
+int __attribute__((target("arch=sandybridge"))) bock4(void) noexcept(true) { return 1;}
+
+// FIXME: Add support for templates and virtual functions!
+template<typename T>
+int __attribute__((target("sse4.2"))) foo(T) { return 0; }
+// expected-error@+3 {{multiversion functions do not yet support function templates}}
+// expected-note@+2 {{function multiversion caused by this declaration}}
+template<typename T>
+int __attribute__((target("arch=sandybridge"))) foo(T);
+
+// expected-error@+3 {{multiversion functions do not yet support function templates}}
+// expected-note@+2 {{function multiversion caused by this declaration}}
+template<typename T>
+int __attribute__((target("default"))) foo(T) { return 2; }
+
+struct S {
+  template<typename T>
+  int __attribute__((target("sse4.2"))) foo(T) { return 0; }
+  // expected-error@+3 {{multiversion functions do not yet support function templates}}
+  // expected-note@+2 {{function multiversion caused by this declaration}}
+  template<typename T>
+  int __attribute__((target("arch=sandybridge"))) foo(T);
+
+  // expected-error@+3 {{multiversion functions do not yet support function templates}}
+  // expected-note@+2 {{function multiversion caused by this declaration}}
+  template<typename T>
+  int __attribute__((target("default"))) foo(T) { return 2; }
+
+  // expected-error@+2 {{multiversion functions do not yet support virtual functions}}
+  // expected-note@+1 {{function multiversion caused by this declaration}}
+  virtual void __attribute__((target("default"))) virt();
+};
+
+extern "C" {
+int __attribute__((target("sse4.2"))) diff_mangle(void) { return 0; }
+}
+//expected-error@+2 {{multiversion function declaration has a different linkage}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("arch=sandybridge"))) diff_mangle(void) { return 0; }
+
+// expected-error@+2 {{multiversion functions do not yet support deduced return types}}
+// expected-note@+1 {{function multiversion caused by this declaration}}
+auto __attribute__((target("default"))) deduced_return(void) { return 0; }
+// expected-error@-1 {{cannot initialize return object of type 'auto' with an rvalue of type 'int'}}
+
+auto __attribute__((target("default"))) trailing_return(void)-> int { return 0; }
+
+__attribute__((target("default"))) void DiffDecl();
+namespace N {
+using ::DiffDecl;
+// expected-error@+3 {{declaration conflicts with target of using declaration already in scope}}
+// expected-note@-4 {{target of using declaration}}
+// expected-note@-3 {{using declaration}}
+__attribute__((target("arch=sandybridge"))) void DiffDecl();
+} // namespace N
Index: test/Sema/attr-target-mv.c
===================================================================
--- /dev/null
+++ test/Sema/attr-target-mv.c
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu  -fsyntax-only -verify %s
+
+void __attribute__((target("sse4.2"))) no_default(void);
+void __attribute__((target("arch=sandybridge")))  no_default(void);
+
+void use1(void){
+  // expected-note@-4 {{candidate ignored: non-default multiversion function cannot be called directly}}
+  // expected-note@-4 {{candidate ignored: non-default multiversion function cannot be called directly}}
+  // expected-error@+1 {{no matching function for call to 'no_default'}}
+  no_default();
+}
+
+int __attribute__((target("sse4.2"))) no_proto();
+// expected-error@-1 {{multiversion function must have a prototype}}
+// expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("arch=sandybridge"))) no_proto();
+
+// The following should all be legal, since they are just redeclarations.
+int __attribute__((target("sse4.2"))) redecl1(void);
+int __attribute__((target("sse4.2"))) redecl1(void) { return 1; }
+int __attribute__((target("arch=sandybridge")))  redecl1(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) redecl2(void) { return 1; }
+int __attribute__((target("sse4.2"))) redecl2(void);
+int __attribute__((target("arch=sandybridge")))  redecl2(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) redecl3(void) { return 0; }
+int __attribute__((target("arch=ivybridge"))) redecl3(void) { return 1; }
+int __attribute__((target("arch=sandybridge")))  redecl3(void);
+int __attribute__((target("arch=sandybridge")))  redecl3(void) { return 2; }
+
+int __attribute__((target("sse4.2"))) redecl4(void) { return 1; }
+int __attribute__((target("arch=sandybridge")))  redecl4(void) { return 2; }
+int __attribute__((target("arch=sandybridge")))  redecl4(void);
+
+int __attribute__((target("sse4.2"))) redef(void) { return 1; }
+int __attribute__((target("arch=ivybridge"))) redef(void) { return 1; }
+int __attribute__((target("arch=sandybridge")))  redef(void) { return 2; }
+// expected-error@+2 {{redefinition of 'redef'}}
+// expected-note@-2 {{previous definition is here}}
+int __attribute__((target("arch=sandybridge")))  redef(void) { return 2; }
+
+int __attribute__((target("default"))) redef2(void) { return 1;}
+// expected-error@+2 {{redefinition of 'redef2'}}
+// expected-note@-2 {{previous definition is here}}
+int __attribute__((target("default"))) redef2(void) { return 1;}
+
+int __attribute__((target("sse4.2"))) mv_after_use(void) { return 1; }
+int use2(void) {
+  return mv_after_use();
+}
+
+// expected-error@+1 {{function declaration cannot become a multiversioned function after first usage}}
+int __attribute__((target("arch=sandybridge")))  mv_after_use(void) { return 2; }
+
+int __attribute__((target("sse4.2,arch=sandybridge"))) mangle(void) { return 1; }
+//expected-error@+2 {{multiversion function redeclarations require identical target attributes}}
+//expected-note@-2 {{previously declared here}}
+int __attribute__((target("arch=sandybridge,sse4.2")))  mangle(void) { return 2; }
+
+int prev_no_target(void);
+int __attribute__((target("arch=sandybridge")))  prev_no_target(void) { return 2; }
+// expected-error@-2 {{function declaration is missing 'target' attribute in a multiversioned function}}
+// expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("arch=ivybridge")))  prev_no_target(void) { return 2; }
+
+int __attribute__((target("arch=sandybridge")))  prev_no_target2(void);
+int prev_no_target2(void);
+// expected-error@-1 {{function declaration is missing 'target' attribute in a multiversioned function}}
+// expected-note@+1 {{function multiversion caused by this declaration}}
+int __attribute__((target("arch=ivybridge")))  prev_no_target2(void);
+
+void __attribute__((target("sse4.2"))) addtl_attrs(void);
+//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+void __attribute__((used,target("arch=sandybridge")))  addtl_attrs(void);
+
+//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
+//expected-note@+1 {{function multiversion caused by this declaration}}
+void __attribute__((target("default"), used)) addtl_attrs2(void);
+
+//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
+//expected-note@+2 {{function multiversion caused by this declaration}}
+void __attribute__((used,target("sse4.2"))) addtl_attrs3(void);
+void __attribute__((target("arch=sandybridge")))  addtl_attrs3(void);
+
+void __attribute__((target("sse4.2"))) addtl_attrs4(void);
+void __attribute__((target("arch=sandybridge")))  addtl_attrs4(void);
+//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
+void __attribute__((used,target("arch=ivybridge")))  addtl_attrs4(void);
+
+int __attribute__((target("sse4.2"))) diff_cc(void);
+// expected-error@+2 {{multiversion function declaration has a different calling convention}}
+// expected-note@+1 {{function multiversion caused by this declaration}}
+__vectorcall int __attribute__((target("arch=sandybridge")))  diff_cc(void);
+
+int __attribute__((target("sse4.2"))) diff_ret(void);
+// expected-error@+2 {{multiversion function declaration has a different return type}}
+// expected-note@+1 {{function multiversion caused by this declaration}}
+short __attribute__((target("arch=sandybridge")))  diff_ret(void);
Index: test/Sema/attr-target-mv-bad-target.c
===================================================================
--- /dev/null
+++ test/Sema/attr-target-mv-bad-target.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-windows-pc  -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple arm-none-eabi  -fsyntax-only -verify %s
+
+int __attribute__((target("sse4.2"))) redecl1(void) { return 1; }
+//expected-error@+2 {{function multiversioning is not supported on the current target}}
+//expected-note@-2 {{previously declared here}}
+int __attribute__((target("avx")))  redecl1(void) { return 2; }
+
+//expected-error@+1 {{function multiversioning is not supported on the current target}}
+int __attribute__((target("default"))) with_def(void) { return 1;}
Index: test/CodeGenCXX/attr-target-mv-overloads.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-target-mv-overloads.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+int __attribute__((target("sse4.2"))) foo_overload(int) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo_overload(int);
+int __attribute__((target("arch=ivybridge"))) foo_overload(int) {return 1;}
+int __attribute__((target("default"))) foo_overload(int) { return 2; }
+int __attribute__((target("sse4.2"))) foo_overload(void) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo_overload(void);
+int __attribute__((target("arch=ivybridge"))) foo_overload(void) {return 1;}
+int __attribute__((target("default"))) foo_overload(void) { return 2; }
+
+int bar2() {
+  return foo_overload() + foo_overload(1);
+}
+
+// CHECK: @_Z12foo_overloadv.ifunc = ifunc i32 (), i32 ()* ()* @_Z12foo_overloadv.resolver
+// CHECK: @_Z12foo_overloadi.ifunc = ifunc i32 (i32), i32 (i32)* ()* @_Z12foo_overloadi.resolver
+
+
+// CHECK: define i32 @_Z12foo_overloadi.sse4.2(i32)
+// CHECK: ret i32 0
+// CHECK: define i32 @_Z12foo_overloadi.arch_ivybridge(i32)
+// CHECK: ret i32 1
+// CHECK: define i32 @_Z12foo_overloadi(i32)
+// CHECK: ret i32 2
+// CHECK: define i32 @_Z12foo_overloadv.sse4.2()
+// CHECK: ret i32 0
+// CHECK: define i32 @_Z12foo_overloadv.arch_ivybridge()
+// CHECK: ret i32 1
+// CHECK: define i32 @_Z12foo_overloadv()
+// CHECK: ret i32 2
+
+// CHECK: define i32 @_Z4bar2v()
+// CHECK: call i32 @_Z12foo_overloadv.ifunc()
+// CHECK: call i32 @_Z12foo_overloadi.ifunc(i32 1)
+
+// CHECK: define i32 ()* @_Z12foo_overloadv.resolver()
+// CHECK: ret i32 ()* @_Z12foo_overloadv.arch_sandybridge
+// CHECK: ret i32 ()* @_Z12foo_overloadv.arch_ivybridge
+// CHECK: ret i32 ()* @_Z12foo_overloadv.sse4.2
+// CHECK: ret i32 ()* @_Z12foo_overloadv
+
+// CHECK: define i32 (i32)* @_Z12foo_overloadi.resolver()
+// CHECK: ret i32 (i32)* @_Z12foo_overloadi.arch_sandybridge
+// CHECK: ret i32 (i32)* @_Z12foo_overloadi.arch_ivybridge
+// CHECK: ret i32 (i32)* @_Z12foo_overloadi.sse4.2
+// CHECK: ret i32 (i32)* @_Z12foo_overloadi
+
+// CHECK: declare i32 @_Z12foo_overloadv.arch_sandybridge()
+// CHECK: declare i32 @_Z12foo_overloadi.arch_sandybridge(i32)
Index: test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+struct S {
+  int __attribute__((target("sse4.2"))) foo(int);
+  int __attribute__((target("arch=sandybridge"))) foo(int);
+  int __attribute__((target("arch=ivybridge"))) foo(int);
+  int __attribute__((target("default"))) foo(int);
+};
+
+int __attribute__((target("default"))) S::foo(int) { return 2; }
+int __attribute__((target("sse4.2"))) S::foo(int) { return 0; }
+int __attribute__((target("arch=ivybridge"))) S::foo(int) { return 1; }
+
+int bar() {
+  S s;
+  return s.foo(0);
+}
+
+// CHECK: @_ZN1S3fooEi.ifunc = ifunc i32 (%struct.S*, i32), i32 (%struct.S*, i32)* ()* @_ZN1S3fooEi.resolver
+
+// CHECK: define i32 @_ZN1S3fooEi(%struct.S* %this, i32)
+// CHECK: ret i32 2
+
+// CHECK: define i32 @_ZN1S3fooEi.sse4.2(%struct.S* %this, i32)
+// CHECK: ret i32 0
+
+// CHECK: define i32 @_ZN1S3fooEi.arch_ivybridge(%struct.S* %this, i32)
+// CHECK: ret i32 1
+
+// CHECK: define i32 @_Z3barv()
+// CHECK: %s = alloca %struct.S, align 1
+// CHECK: %call = call i32 @_ZN1S3fooEi.ifunc(%struct.S* %s, i32 0)
+
+// CHECK: define i32 (%struct.S*, i32)* @_ZN1S3fooEi.resolver()
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_sandybridge
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_ivybridge
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.sse4.2
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi
+
+// CHECK: declare i32 @_ZN1S3fooEi.arch_sandybridge(%struct.S*, i32)
Index: test/CodeGenCXX/attr-target-mv-member-funcs.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-target-mv-member-funcs.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+struct S {
+  int __attribute__((target("sse4.2"))) foo(int) { return 0; }
+  int __attribute__((target("arch=sandybridge"))) foo(int);
+  int __attribute__((target("arch=ivybridge"))) foo(int) { return 1; }
+  int __attribute__((target("default"))) foo(int) { return 2; }
+};
+
+int bar() {
+  S s;
+  return s.foo(0);
+}
+
+// CHECK: @_ZN1S3fooEi.ifunc = ifunc i32 (%struct.S*, i32), i32 (%struct.S*, i32)* ()* @_ZN1S3fooEi.resolver
+
+// CHECK: define i32 @_Z3barv()
+// CHECK: %s = alloca %struct.S, align 1
+// CHECK: %call = call i32 @_ZN1S3fooEi.ifunc(%struct.S* %s, i32 0)
+
+// CHECK: define i32 (%struct.S*, i32)* @_ZN1S3fooEi.resolver()
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_sandybridge
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.arch_ivybridge
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi.sse4.2
+// CHECK: ret i32 (%struct.S*, i32)* @_ZN1S3fooEi
+
+// CHECK: define linkonce_odr i32 @_ZN1S3fooEi.sse4.2(%struct.S* %this, i32)
+// CHECK: ret i32 0
+
+// CHECK: declare i32 @_ZN1S3fooEi.arch_sandybridge(%struct.S*, i32)
+
+// CHECK: define linkonce_odr i32 @_ZN1S3fooEi.arch_ivybridge(%struct.S* %this, i32)
+// CHECK: ret i32 1
+
+// CHECK: define linkonce_odr i32 @_ZN1S3fooEi(%struct.S* %this, i32)
+// CHECK: ret i32 2
+
Index: test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+void temp();
+void temp(int);
+using FP = void(*)(int);
+void b() {
+  FP f = temp; 
+}
+
+int __attribute__((target("sse4.2"))) foo(int) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(int);
+int __attribute__((target("arch=ivybridge"))) foo(int) {return 1;}
+int __attribute__((target("default"))) foo(int) { return 2; }
+
+struct S {
+int __attribute__((target("sse4.2"))) foo(int) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(int);
+int __attribute__((target("arch=ivybridge"))) foo(int) {return 1;}
+int __attribute__((target("default"))) foo(int) { return 2; }
+};
+
+using FuncPtr = int (*)(int);
+using MemFuncPtr = int (S::*)(int);
+
+void f(FuncPtr, MemFuncPtr);
+
+int bar() {
+  FuncPtr Free = &foo;
+  MemFuncPtr Member = &S::foo;
+  S s;
+  f(foo, &S::foo);
+  return Free(1) + (s.*Member)(2);
+}
+
+
+// CHECK: @_Z3fooi.ifunc 
+// CHECK: @_ZN1S3fooEi.ifunc
+
+// CHECK: define i32 @_Z3barv()
+// Store to Free of ifunc
+// CHECK: store i32 (i32)* @_Z3fooi.ifunc
+// Store to Member of ifunc
+// CHECK: store { i64, i64 } { i64 ptrtoint (i32 (%struct.S*, i32)* @_ZN1S3fooEi.ifunc to i64), i64 0 }, { i64, i64 }* [[MEMBER:%[a-z]+]]
+
+// Call to 'f' with the ifunc
+// CHECK: call void @_Z1fPFiiEM1SFiiE(i32 (i32)* @_Z3fooi.ifunc
Index: test/CodeGenCXX/attr-target-mv-diff-ns.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-target-mv-diff-ns.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// Test ensures that this properly differentiates between types in different 
+// namespaces.
+int __attribute__((target("sse4.2"))) foo(int) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(int);
+int __attribute__((target("arch=ivybridge"))) foo(int) {return 1;}
+int __attribute__((target("default"))) foo(int) { return 2; }
+
+namespace ns {
+int __attribute__((target("sse4.2"))) foo(int) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(int);
+int __attribute__((target("arch=ivybridge"))) foo(int) {return 1;}
+int __attribute__((target("default"))) foo(int) { return 2; }
+}
+
+int bar() {
+  return foo(1) + ns::foo(2);
+}
+
+// CHECK: @_Z3fooi.ifunc = ifunc i32 (i32), i32 (i32)* ()* @_Z3fooi.resolver
+// CHECK: @_ZN2ns3fooEi.ifunc = ifunc i32 (i32), i32 (i32)* ()* @_ZN2ns3fooEi.resolver
+
+// CHECK: define i32 @_Z3fooi.sse4.2(i32)
+// CHECK: ret i32 0
+// CHECK: define i32 @_Z3fooi.arch_ivybridge(i32)
+// CHECK: ret i32 1
+// CHECK: define i32 @_Z3fooi(i32)
+// CHECK: ret i32 2
+
+// CHECK: define i32 @_ZN2ns3fooEi.sse4.2(i32)
+// CHECK: ret i32 0
+// CHECK: define i32 @_ZN2ns3fooEi.arch_ivybridge(i32)
+// CHECK: ret i32 1
+// CHECK: define i32 @_ZN2ns3fooEi(i32)
+// CHECK: ret i32 2
+
+// CHECK: define i32 @_Z3barv()
+// CHECK: call i32 @_Z3fooi.ifunc(i32 1)
+// CHECK: call i32 @_ZN2ns3fooEi.ifunc(i32 2)
+
+// CHECK: define i32 (i32)* @_Z3fooi.resolver()
+// CHECK: ret i32 (i32)* @_Z3fooi.arch_sandybridge
+// CHECK: ret i32 (i32)* @_Z3fooi.arch_ivybridge
+// CHECK: ret i32 (i32)* @_Z3fooi.sse4.2
+// CHECK: ret i32 (i32)* @_Z3fooi
+//
+// CHECK: define i32 (i32)* @_ZN2ns3fooEi.resolver()
+// CHECK: ret i32 (i32)* @_ZN2ns3fooEi.arch_sandybridge
+// CHECK: ret i32 (i32)* @_ZN2ns3fooEi.arch_ivybridge
+// CHECK: ret i32 (i32)* @_ZN2ns3fooEi.sse4.2
+// CHECK: ret i32 (i32)* @_ZN2ns3fooEi
+
+// CHECK: declare i32 @_Z3fooi.arch_sandybridge(i32)
+// CHECK: declare i32 @_ZN2ns3fooEi.arch_sandybridge(i32)
Index: test/CodeGenCXX/attr-target-mv-constexpr.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-target-mv-constexpr.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+constexpr int __attribute__((target("sse4.2"))) foo(void) { return 0; }
+constexpr int __attribute__((target("arch=sandybridge"))) foo(void);
+constexpr int __attribute__((target("arch=ivybridge"))) foo(void) {return 1;}
+constexpr int __attribute__((target("default"))) foo(void) { return 2; }
+
+int bar() {
+  constexpr int i = foo();
+  return i;
+}
+
+// CHECK-NOT: foo
+// CHECK: define i32 @_Z3barv()
+// CHECK: ret i32 2
+// CHECK-NOT: foo
Index: test/CodeGen/attr-target-mv.c
===================================================================
--- /dev/null
+++ test/CodeGen/attr-target-mv.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+int __attribute__((target("sse4.2"))) foo(void) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(void);
+int __attribute__((target("arch=ivybridge"))) foo(void) {return 1;}
+int __attribute__((target("default"))) foo(void) { return 2; }
+
+int bar() {
+  return foo();
+}
+
+inline int __attribute__((target("sse4.2"))) foo_inline(void) { return 0; }
+inline int __attribute__((target("arch=sandybridge"))) foo_inline(void);
+inline int __attribute__((target("arch=ivybridge"))) foo_inline(void) {return 1;}
+inline int __attribute__((target("default"))) foo_inline(void) { return 2; }
+
+int bar2() {
+  return foo_inline();
+}
+
+// CHECK: @foo.ifunc = ifunc i32 (), i32 ()* ()* @foo.resolver
+// CHECK: @foo_inline.ifunc = ifunc i32 (), i32 ()* ()* @foo_inline.resolver
+
+// CHECK: define i32 @foo.sse4.2()
+// CHECK: ret i32 0
+// CHECK: define i32 @foo.arch_ivybridge()
+// CHECK: ret i32 1
+// CHECK: define i32 @foo()
+// CHECK: ret i32 2
+// CHECK: define i32 @bar()
+// CHECK: call i32 @foo.ifunc()
+
+// CHECK: define i32 ()* @foo.resolver()
+// CHECK: call void @__cpu_indicator_init()
+// CHECK: ret i32 ()* @foo.arch_sandybridge
+// CHECK: ret i32 ()* @foo.arch_ivybridge
+// CHECK: ret i32 ()* @foo.sse4.2
+// CHECK: ret i32 ()* @foo
+
+// CHECK: define i32 @bar2()
+// CHECK: call i32 @foo_inline.ifunc()
+
+// CHECK: define i32 ()* @foo_inline.resolver()
+// CHECK: call void @__cpu_indicator_init()
+// CHECK: ret i32 ()* @foo_inline.arch_sandybridge
+// CHECK: ret i32 ()* @foo_inline.arch_ivybridge
+// CHECK: ret i32 ()* @foo_inline.sse4.2
+// CHECK: ret i32 ()* @foo_inline
+
+// CHECK: declare i32 @foo.arch_sandybridge()
+
+// CHECK: define available_externally i32 @foo_inline.sse4.2()
+// CHECK: ret i32 0
+
+// CHECK: declare i32 @foo_inline.arch_sandybridge()
+//
+// CHECK: define available_externally i32 @foo_inline.arch_ivybridge()
+// CHECK: ret i32 1
+// CHECK: define available_externally i32 @foo_inline()
+// CHECK: ret i32 2
+
+
Index: test/CodeGen/attr-target-mv-va-args.c
===================================================================
--- /dev/null
+++ test/CodeGen/attr-target-mv-va-args.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+int __attribute__((target("sse4.2"))) foo(int i, ...) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(int i, ...);
+int __attribute__((target("arch=ivybridge"))) foo(int i, ...) {return 1;}
+int __attribute__((target("default"))) foo(int i, ...) { return 2; }
+
+int bar() {
+  return foo(1, 'a', 1.1) + foo(2, 2.2, "asdf");
+}
+
+// CHECK: @foo.ifunc = ifunc i32 (i32, ...), i32 (i32, ...)* ()* @foo.resolver
+// CHECK: define i32 @foo.sse4.2(i32 %i, ...)
+// CHECK: ret i32 0
+// CHECK: define i32 @foo.arch_ivybridge(i32 %i, ...)
+// CHECK: ret i32 1
+// CHECK: define i32 @foo(i32 %i, ...)
+// CHECK: ret i32 2
+// CHECK: define i32 @bar()
+// CHECK: call i32 (i32, ...) @foo.ifunc(i32 1, i32 97, double
+// CHECK: call i32 (i32, ...) @foo.ifunc(i32 2, double 2.2{{[0-9Ee+]+}}, i8* getelementptr inbounds 
+// CHECK: define i32 (i32, ...)* @foo.resolver()
+// CHECK: ret i32 (i32, ...)* @foo.arch_sandybridge
+// CHECK: ret i32 (i32, ...)* @foo.arch_ivybridge
+// CHECK: ret i32 (i32, ...)* @foo.sse4.2
+// CHECK: ret i32 (i32, ...)* @foo
+// CHECK: declare i32 @foo.arch_sandybridge(i32, ...)
Index: test/CodeGen/attr-target-mv-func-ptrs.c
===================================================================
--- /dev/null
+++ test/CodeGen/attr-target-mv-func-ptrs.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+int __attribute__((target("sse4.2"))) foo(int i) { return 0; }
+int __attribute__((target("arch=sandybridge"))) foo(int);
+int __attribute__((target("arch=ivybridge"))) foo(int i) {return 1;}
+int __attribute__((target("default"))) foo(int i) { return 2; }
+
+typedef int (*FuncPtr)(int);
+void func(FuncPtr);
+
+int bar() {
+  func(foo);
+  FuncPtr Free = &foo;
+  FuncPtr Free2 = foo;
+  return Free(1) + Free(2);
+}
+
+// CHECK: @foo.ifunc = ifunc i32 (i32), i32 (i32)* ()* @foo.resolver
+// CHECK: define i32 @foo.sse4.2(
+// CHECK: ret i32 0
+// CHECK: define i32 @foo.arch_ivybridge(
+// CHECK: ret i32 1
+// CHECK: define i32 @foo(
+// CHECK: ret i32 2
+
+// CHECK: define i32 @bar()
+// CHECK: call void @func(i32 (i32)* @foo.ifunc)
+// CHECK: store i32 (i32)* @foo.ifunc
+// CHECK: store i32 (i32)* @foo.ifunc
+
+// CHECK: declare i32 @foo.arch_sandybridge(
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -534,6 +534,7 @@
   Record.push_back(D->IsConstexpr);
   Record.push_back(D->UsesSEHTry);
   Record.push_back(D->HasSkippedBody);
+  Record.push_back(D->IsMultiVersion);
   Record.push_back(D->IsLateTemplateParsed);
   Record.push_back(D->getLinkageInternal());
   Record.AddSourceLocation(D->getLocEnd());
@@ -2071,6 +2072,7 @@
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constexpr
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // UsesSEHTry
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // MultiVersion
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // LocEnd
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -792,6 +792,7 @@
   FD->IsConstexpr = Record.readInt();
   FD->UsesSEHTry = Record.readInt();
   FD->HasSkippedBody = Record.readInt();
+  FD->IsMultiVersion = Record.readInt();
   FD->IsLateTemplateParsed = Record.readInt();
   FD->setCachedLinkage(Linkage(Record.readInt()));
   FD->EndRangeLoc = ReadSourceLocation();
@@ -2814,6 +2815,15 @@
                         CtorY->getInheritedConstructor().getConstructor()))
         return false;
     }
+    // Multiversioned functions with different 
+    if (FuncX->isMultiVersion()) {
+      const auto *TAX = FuncX->getAttr<TargetAttr>();
+      const auto *TAY = FuncY->getAttr<TargetAttr>();
+      assert(TAX && TAY && "Multiversion Function without target attribute");
+
+      if(TAX->getFeaturesStr() != TAY->getFeaturesStr())
+        return false;
+    }
     ASTContext &C = FuncX->getASTContext();
     if (!C.hasSameType(FuncX->getType(), FuncY->getType())) {
       // We can get functions with different types on the redecl chain in C++17
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -5940,6 +5940,13 @@
   Candidate.IgnoreObjectArgument = false;
   Candidate.ExplicitCallArguments = Args.size();
 
+  if (Function->isMultiVersion() &&
+      Function->getAttr<TargetAttr>()->getFeaturesStr() != "default") {
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_non_default_multiversion_function;
+    return;
+  }
+
   if (Constructor) {
     // C++ [class.copy]p3:
     //   A member function template is never instantiated to perform the copy
@@ -6564,6 +6571,12 @@
     Candidate.DeductionFailure.Data = FailedAttr;
     return;
   }
+
+  if (Method->isMultiVersion() &&
+      Method->getAttr<TargetAttr>()->getFeaturesStr() != "default") {
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_non_default_multiversion_function;
+  }
 }
 
 /// \brief Add a C++ member function template as a candidate to the candidate
@@ -10176,6 +10189,9 @@
     assert(!Available);
     break;
   }
+  case ovl_non_default_multiversion_function:
+    S.Diag(Fn->getLocation(), diag::note_ovl_candidate_nondefault_multiversion);
+    break;
   }
 }
 
@@ -10912,6 +10928,12 @@
         if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext))
           if (!Caller->isImplicit() && !S.IsAllowedCUDACall(Caller, FunDecl))
             return false;
+      if (FunDecl->isMultiVersion()) {
+        const auto *TA = FunDecl->getAttr<TargetAttr>();
+        assert(TA && "MultiVersion requires a target attribute");
+        if (TA->getFeaturesStr() != "default")
+          return false;
+      }
 
       // If any candidate has a placeholder return type, trigger its deduction
       // now.
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -9287,6 +9287,348 @@
            D->getFriendObjectKind() != Decl::FOK_None);
 }
 
+/// \brief Check the target attribute of the function for MultiVersion
+/// validity.
+///
+/// Returns true if there was an error, false otherwise.
+static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
+  const auto *TA = FD->getAttr<TargetAttr>();
+  assert(TA && "MultiVersion Candidate requires a target attribute");
+  TargetAttr::ParsedTargetAttr ParseInfo = TA->parse();
+  const TargetInfo &TargetInfo = S.Context.getTargetInfo();
+  enum ErrType { Feature = 0, Architecture = 1 };
+
+  if (!ParseInfo.Architecture.empty() &&
+      !TargetInfo.validateCpuIs(ParseInfo.Architecture)) {
+    S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+        << Architecture << ParseInfo.Architecture;
+    return true;
+  }
+
+  for (const auto &Feature : ParseInfo.Features) {
+    auto BareFeat = StringRef{Feature}.substr(1);
+    if (Feature[0] == '-') {
+      S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+          << Feature << ("no-" + BareFeat).str();
+      return true;
+    }
+
+    if (!TargetInfo.validateCpuSupports(BareFeat) ||
+        !TargetInfo.isValidFeatureName(BareFeat)) {
+      S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+          << Feature << BareFeat;
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
+                                             const FunctionDecl *NewFD,
+                                             bool CausesMV) {
+  enum DoesntSupport { FuncTemplates = 0, VirtFuncs = 1, DeducedReturn = 2 };
+  enum Different {
+    CallingConv = 0,
+    ReturnType = 1,
+    ConstexprSpec = 2,
+    InlineSpec = 3,
+    StorageClass = 4,
+    Linkage = 5
+  };
+
+  // For now, disallow all other attributes.  These should be opt-in, but
+  // an analysis of all of them is a future FIXME.
+  if (CausesMV && OldFD &&
+      std::distance(OldFD->attr_begin(), OldFD->attr_end()) != 1) {
+    S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs);
+    S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+    return true;
+  }
+
+  if (std::distance(NewFD->attr_begin(), NewFD->attr_end()) != 1) {
+    S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs);
+    if (CausesMV)
+      S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+    return true;
+  }
+
+  if (NewFD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) {
+    S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
+        << FuncTemplates;
+    if (CausesMV)
+      S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+    return true;
+  }
+
+  if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) {
+    if (NewCXXFD->isVirtual()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
+          << VirtFuncs;
+      if (CausesMV)
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+  }
+
+  QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType());
+  const auto *NewType = cast<FunctionType>(NewQType);
+  QualType NewReturnType = NewType->getReturnType();
+
+  if (NewReturnType->isUndeducedType()) {
+    S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
+        << DeducedReturn;
+    if (CausesMV)
+      S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+    return true;
+  }
+
+  // Only allow transition to MultiVersion if it hasn't been used.
+  if (OldFD && CausesMV && OldFD->isUsed(false)) {
+    S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used);
+    return true;
+  }
+
+  // Ensure the return type is identical.
+  if (OldFD) {
+    QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType());
+    const auto *OldType = cast<FunctionType>(OldQType);
+    FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
+    FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
+
+    if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) << CallingConv;
+      S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+
+    QualType OldReturnType = OldType->getReturnType();
+
+    if (OldReturnType != NewReturnType) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) << ReturnType;
+      if (CausesMV)
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+
+    if (OldFD->isConstexpr() != NewFD->isConstexpr()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
+          << ConstexprSpec;
+      if (CausesMV)
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+
+    if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) << InlineSpec;
+      if (CausesMV)
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+
+    if (OldFD->getStorageClass() != NewFD->getStorageClass()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) << StorageClass;
+      if (CausesMV)
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+
+    if (OldFD->isExternC() != NewFD->isExternC()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) << Linkage;
+      if (CausesMV)
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      return true;
+    }
+
+    if (S.CheckEquivalentExceptionSpec(
+            OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(),
+            NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation()))
+      return true;
+  }
+  return false;
+}
+
+/// \brief Check the validity of a mulitversion function declaration.
+/// Also sets the multiversion'ness' of the function itself.
+///
+/// This sets NewFD->isInvalidDecl() to true if there was an error.
+///
+/// Returns true if there was an error, false otherwise.
+static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
+                                      bool &Redeclaration, NamedDecl *&OldDecl,
+                                      bool &MayNeedOverloadableChecks,
+                                      LookupResult &Previous) {
+  const auto *NewTA = NewFD->getAttr<TargetAttr>();
+  if (NewFD->isMain()) {
+    if (NewTA && NewTA->getFeaturesStr() == "default") {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main);
+      NewFD->isInvalidDecl();
+      return true;
+    }
+    return false;
+  }
+
+  // If there is no matching previous decl, only 'default' can
+  // cause MultiVersioning.
+  if (!OldDecl) {
+    if (NewTA && NewTA->getFeaturesStr() == "default") {
+      if (!NewFD->getType()->getAs<FunctionProtoType>()) {
+        S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto);
+        NewFD->setInvalidDecl();
+        return true;
+      }
+      if (CheckMultiVersionAdditionalRules(S, nullptr, NewFD, true)) {
+        NewFD->setInvalidDecl();
+        return true;
+      }
+      if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
+        S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
+        return true;
+      }
+
+      NewFD->setIsMultiVersion();
+    }
+    return false;
+  }
+
+  if (OldDecl->getDeclContext()->getRedeclContext() !=
+      NewFD->getDeclContext()->getRedeclContext())
+    return false;
+
+  FunctionDecl *OldFD = OldDecl->getAsFunction();
+  // Unresolved 'using' statements (the other way OldDecl can be not a function)
+  // likely cannot cause a problem here.
+  if (!OldFD)
+    return false;
+
+  if (!OldFD->isMultiVersion() && !NewTA)
+    return false;
+
+  if (OldFD->isMultiVersion() && !NewTA) {
+    S.Diag(NewFD->getLocation(), diag::err_target_required_in_redecl);
+    NewFD->setInvalidDecl();
+    return true;
+  }
+
+  TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse();
+  // Sort order doesn't matter, it just needs to be consistent.
+  std::sort(NewParsed.Features.begin(), NewParsed.Features.end());
+
+  const auto *OldTA = OldFD->getAttr<TargetAttr>();
+  if (!OldFD->isMultiVersion()) {
+    // If the old decl is NOT MultiVersioned yet, and we don't cause that
+    // to change, this is a simple redeclaration.
+    if (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())
+      return false;
+
+    // Otherwise, this decl causes MultiVersioning.
+    if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
+      S.Diag(OldFD->getLocation(), diag::note_previous_decl) << "previously";
+      return true;
+    }
+
+    if (!NewFD->getType()->getAs<FunctionProtoType>()) {
+      S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto);
+      S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      NewFD->setInvalidDecl();
+      return true;
+    }
+
+    if (CheckMultiVersionValue(S, NewFD)) {
+      NewFD->setInvalidDecl();
+      return true;
+    }
+
+    if (CheckMultiVersionValue(S, OldFD)) {
+      S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+      NewFD->setInvalidDecl();
+      return true;
+    }
+
+    TargetAttr::ParsedTargetAttr OldParsed =
+        OldTA->parse(std::less<std::string>());
+
+    if (OldParsed == NewParsed) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+      S.Diag(OldFD->getLocation(), diag::note_previous_decl) << "previously";
+      NewFD->setInvalidDecl();
+      return true;
+    }
+
+    for (const auto *FD : OldFD->redecls()) {
+      const auto *CurTA = FD->getAttr<TargetAttr>();
+      if (!CurTA || CurTA->isInherited()) {
+        S.Diag(FD->getLocation(), diag::err_target_required_in_redecl);
+        S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+        NewFD->setInvalidDecl();
+        return true;
+      }
+    }
+
+    if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true)) {
+      NewFD->setInvalidDecl();
+      return true;
+    }
+
+    OldFD->setIsMultiVersion();
+    NewFD->setIsMultiVersion();
+    Redeclaration = false;
+    MayNeedOverloadableChecks = false;
+    OldDecl = nullptr;
+    Previous.clear();
+    return false;
+  }
+
+  bool UseMemberUsingDeclRules =
+      S.CurContext->isRecord() && !NewFD->getFriendObjectKind();
+
+  // Next, check ALL non-overloads to see if this is a redeclaration of a
+  // previous member of the MultiVersion set.
+  for (NamedDecl *ND : Previous) {
+    FunctionDecl *CurFD = ND->getAsFunction();
+    if (!CurFD)
+      continue;
+    if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
+      continue;
+
+    const auto *CurTA = CurFD->getAttr<TargetAttr>();
+    if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) {
+      NewFD->setIsMultiVersion();
+      Redeclaration = true;
+      OldDecl = ND;
+      return false;
+    }
+
+    TargetAttr::ParsedTargetAttr CurParsed =
+        CurTA->parse(std::less<std::string>());
+
+    if (CurParsed == NewParsed) {
+      S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+      S.Diag(CurFD->getLocation(), diag::note_previous_decl) << "previously";
+      NewFD->setInvalidDecl();
+      return true;
+    }
+  }
+
+  // Else, this is simply a non-redecl case.
+  if (CheckMultiVersionValue(S, NewFD)) {
+    NewFD->setInvalidDecl();
+    return true;
+  }
+
+  if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, false)) {
+    NewFD->setInvalidDecl();
+    return true;
+  }
+
+  NewFD->setIsMultiVersion();
+  Redeclaration = false;
+  MayNeedOverloadableChecks = false;
+  OldDecl = nullptr;
+  Previous.clear();
+  return false;
+}
+
 /// \brief Perform semantic checking of a new function declaration.
 ///
 /// Performs semantic analysis of the new function declaration
@@ -9374,6 +9716,10 @@
     }
   }
 
+  if (CheckMultiVersionFunction(*this, NewFD, Redeclaration, OldDecl,
+                                MergeTypeWithPrevious, Previous))
+    return Redeclaration;
+
   // C++11 [dcl.constexpr]p8:
   //   A constexpr specifier for a non-static member function that is not
   //   a constructor declares that member function to be const.
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -324,6 +324,10 @@
   /// is defined once we get to the end of the of the translation unit.
   std::vector<GlobalDecl> Aliases;
 
+  /// List of multiversion functions that have to be emitted.  Used to make sure
+  /// we properly emit the iFunc.
+  std::vector<GlobalDecl> MultiVersionFuncs;
+
   typedef llvm::StringMap<llvm::TrackingVH<llvm::Constant> > ReplacementsTy;
   ReplacementsTy Replacements;
 
@@ -1247,6 +1251,12 @@
       llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
       ForDefinition_t IsForDefinition = NotForDefinition);
 
+  llvm::Constant *GetOrCreateMultiVersionIFunc(GlobalDecl GD,
+                                               llvm::Type *DeclTy,
+                                               StringRef MangledName,
+                                               const FunctionDecl *FD);
+  void UpdateMultiVersionNames(GlobalDecl GD, const NamedDecl *ND);
+
   llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
                                         llvm::PointerType *PTy,
                                         const VarDecl *D,
@@ -1319,6 +1329,8 @@
 
   void checkAliases();
 
+  void emitMultiVersionFunctions();
+
   /// Emit any vtables which we deferred and still have a use for.
   void EmitDeferredVTables();
 
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -391,6 +391,7 @@
   applyGlobalValReplacements();
   applyReplacements();
   checkAliases();
+  emitMultiVersionFunctions();
   EmitCXXGlobalInitFunc();
   EmitCXXGlobalDtorFunc();
   EmitCXXThreadLocalInitFunc();
@@ -721,36 +722,48 @@
   GV->setThreadLocalMode(TLM);
 }
 
-StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
-  GlobalDecl CanonicalGD = GD.getCanonicalDecl();
+static void AppendTargetMangling(const CodeGenModule &CGM,
+                                 const TargetAttr *Attr, raw_ostream &Out) {
+  if (Attr->getFeaturesStr() == "default")
+    return;
 
-  // Some ABIs don't have constructor variants.  Make sure that base and
-  // complete constructors get mangled the same.
-  if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
-    if (!getTarget().getCXXABI().hasConstructorVariants()) {
-      CXXCtorType OrigCtorType = GD.getCtorType();
-      assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
-      if (OrigCtorType == Ctor_Base)
-        CanonicalGD = GlobalDecl(CD, Ctor_Complete);
-    }
+  Out << '.';
+  const auto &Target = CGM.getTarget();
+  TargetAttr::ParsedTargetAttr Info =
+      Attr->parse([&Target](StringRef LHS, StringRef RHS) {
+                    return Target.multiVersionSortPriority(LHS) >
+                           Target.multiVersionSortPriority(RHS);
+                  });
+
+  bool IsFirst = true;
+
+  if (!Info.Architecture.empty()) {
+    IsFirst = false;
+    Out << "arch_" << Info.Architecture;
   }
 
-  auto FoundName = MangledDeclNames.find(CanonicalGD);
-  if (FoundName != MangledDeclNames.end())
-    return FoundName->second;
+  for (StringRef Feat : Info.Features) {
+    if (!IsFirst)
+      Out << '_';
+    IsFirst = false;
+    Out << Feat.substr(1);
+  }
+}
 
-  const auto *ND = cast<NamedDecl>(GD.getDecl());
+static std::string getMangledNameImpl(const CodeGenModule &CGM, GlobalDecl GD,
+                                      const NamedDecl *ND,
+                                      bool OmitTargetMangling = false) {
   SmallString<256> Buffer;
-  StringRef Str;
-  if (getCXXABI().getMangleContext().shouldMangleDeclName(ND)) {
+  llvm::raw_svector_ostream Out(Buffer);
+  MangleContext &MC = CGM.getCXXABI().getMangleContext();
+  if (MC.shouldMangleDeclName(ND)) {
     llvm::raw_svector_ostream Out(Buffer);
     if (const auto *D = dyn_cast<CXXConstructorDecl>(ND))
-      getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out);
+      MC.mangleCXXCtor(D, GD.getCtorType(), Out);
     else if (const auto *D = dyn_cast<CXXDestructorDecl>(ND))
-      getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out);
+      MC.mangleCXXDtor(D, GD.getDtorType(), Out);
     else
-      getCXXABI().getMangleContext().mangleName(ND, Out);
-    Str = Out.str();
+      MC.mangleName(ND, Out);
   } else {
     IdentifierInfo *II = ND->getIdentifier();
     assert(II && "Attempt to mangle unnamed decl.");
@@ -760,14 +773,76 @@
         FD->getType()->castAs<FunctionType>()->getCallConv() == CC_X86RegCall) {
       llvm::raw_svector_ostream Out(Buffer);
       Out << "__regcall3__" << II->getName();
-      Str = Out.str();
     } else {
-      Str = II->getName();
+      Out << II->getName();
     }
   }
 
+  if (const auto *FD = dyn_cast<FunctionDecl>(ND))
+    if (FD->isMultiVersion() && !OmitTargetMangling)
+      AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out);
+  return Out.str();
+}
+
+void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD,
+                                            const NamedDecl *ND) {
+  const auto *FD = dyn_cast<FunctionDecl>(ND);
+  if (!FD || !FD->isMultiVersion())
+    return;
+
+  // Get the name of what this would be without the 'target' attribute.  This
+  // allows us to lookup the version that was emitted when this wasn't a
+  // multiversion function.
+  std::string NonTargetName =
+      getMangledNameImpl(*this, GD, ND, /*OmitTargetMangling=*/true);
+  GlobalDecl OtherGD;
+  if (lookupRepresentativeDecl(NonTargetName, OtherGD)) {
+    assert(OtherGD.getCanonicalDecl()
+               .getDecl()
+               ->getAsFunction()
+               ->isMultiVersion() &&
+           "Other GD should now be a multiversioned function");
+    // OtherFD is the version of this function that was mangled BEFORE
+    // becoming a MultiVersion function.  It potentially needs to be updated.
+    const FunctionDecl *OtherFD =
+        OtherGD.getCanonicalDecl().getDecl()->getAsFunction();
+    std::string OtherName = getMangledNameImpl(*this, OtherGD, OtherFD);
+    // This is so that if the initial version was already the 'default'
+    // version, we don't try to update it.
+    if (OtherName != NonTargetName) {
+      Manglings.erase(NonTargetName);
+      auto Result = Manglings.insert(std::make_pair(OtherName, OtherGD));
+      MangledDeclNames[OtherGD.getCanonicalDecl()] = Result.first->first();
+      if (llvm::GlobalValue *Entry = GetGlobalValue(NonTargetName))
+        Entry->setName(OtherName);
+    }
+  }
+}
+
+StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
+  GlobalDecl CanonicalGD = GD.getCanonicalDecl();
+
+  // Some ABIs don't have constructor variants.  Make sure that base and
+  // complete constructors get mangled the same.
+  if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
+    if (!getTarget().getCXXABI().hasConstructorVariants()) {
+      CXXCtorType OrigCtorType = GD.getCtorType();
+      assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
+      if (OrigCtorType == Ctor_Base)
+        CanonicalGD = GlobalDecl(CD, Ctor_Complete);
+    }
+  }
+
+  auto FoundName = MangledDeclNames.find(CanonicalGD);
+  if (FoundName != MangledDeclNames.end())
+    return FoundName->second;
+
+  const auto *ND = cast<NamedDecl>(GD.getDecl());
+  UpdateMultiVersionNames(GD, ND);
+
   // Keep the first result in the case of a mangling collision.
-  auto Result = Manglings.insert(std::make_pair(Str, GD));
+  auto Result =
+      Manglings.insert(std::make_pair(getMangledNameImpl(*this, GD, ND), GD));
   return MangledDeclNames[CanonicalGD] = Result.first->first();
 }
 
@@ -1978,6 +2053,8 @@
   if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
     return true;
   const auto *F = cast<FunctionDecl>(GD.getDecl());
+  if (F->isMultiVersion())
+    return true;
   if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr<AlwaysInlineAttr>())
     return false;
 
@@ -2054,6 +2131,79 @@
 static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
                                                       llvm::Function *NewFn);
 
+void CodeGenModule::emitMultiVersionFunctions() {
+  for (GlobalDecl GD : MultiVersionFuncs) {
+    const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+
+    SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
+
+    for (auto *CurDecl : FD->getDeclContext()->getRedeclContext()->lookup(
+             FD->getDeclName())) {
+      if (const auto *CurFD = dyn_cast<FunctionDecl>(CurDecl))
+        if (getContext().hasSameType(CurFD->getType(), FD->getType())) {
+          StringRef MangledName = getMangledName(CurFD);
+          llvm::Constant *Func = GetGlobalValue(MangledName);
+
+          if (!Func) {
+            GlobalDecl CurGD{CurFD};
+            if (CurFD->isDefined()) {
+              EmitGlobalDefinition(CurGD);
+              Func = GetGlobalValue(MangledName);
+            } else {
+              const CGFunctionInfo &FI =
+                  getTypes().arrangeGlobalDeclaration(GD);
+              llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
+              Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
+                                       /*DontDefer=*/false, ForDefinition);
+            }
+            assert(Func && "This should have just been created");
+          }
+          Options.emplace_back(getTarget(), cast<llvm::Function>(Func),
+                               CurFD->getAttr<TargetAttr>()->parse());
+        }
+    }
+
+    llvm::Function *ResolverFunc = cast<llvm::Function>(
+        GetGlobalValue((getMangledName(FD) + ".resolver").str()));
+    std::stable_sort(
+        Options.begin(), Options.end(),
+        std::greater<CodeGenFunction::MultiVersionResolverOption>());
+    CodeGenFunction CGF(*this);
+    CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+  }
+}
+
+/// If an ifunc for the specified mangled name is not in the module, create and
+/// return an llvm IFunc Function with the specified type.
+llvm::Constant *
+CodeGenModule::GetOrCreateMultiVersionIFunc(GlobalDecl GD, llvm::Type *DeclTy,
+                                            StringRef MangledName,
+                                            const FunctionDecl *FD) {
+  std::string IFuncName = (MangledName + ".ifunc").str();
+  if (llvm::GlobalValue *IFuncGV = GetGlobalValue(IFuncName))
+    return IFuncGV;
+
+  // Since this is the first time we've created this IFunc, make sure
+  // that we put this multiversioned function into the list to be
+  // replaced later.
+  MultiVersionFuncs.push_back(GD);
+
+  std::string ResolverName = (MangledName + ".resolver").str();
+  llvm::Type *ResolverType = llvm::FunctionType::get(
+      llvm::PointerType::get(DeclTy,
+                             Context.getTargetAddressSpace(FD->getType())),
+      false);
+  llvm::Constant *Resolver =
+      GetOrCreateLLVMFunction(ResolverName, ResolverType, GlobalDecl{},
+                              /*ForVTable=*/false);
+  llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(
+      DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule());
+  GIF->setName(IFuncName);
+  SetCommonAttributes(FD, GIF);
+
+  return GIF;
+}
+
 /// GetOrCreateLLVMFunction - If the specified mangled name is not in the
 /// module, create and return an llvm Function with the specified type. If there
 /// is something in the module with the specified name, return it potentially
@@ -2067,6 +2217,12 @@
     ForDefinition_t IsForDefinition) {
   const Decl *D = GD.getDecl();
 
+  // Any attempts to use a MultiVersion function should result in retrieving
+  // the iFunc instead. Name Mangling will handle the rest of the changes.
+  if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D))
+    if (FD->isMultiVersion() && !IsForDefinition)
+      return GetOrCreateMultiVersionIFunc(GD, Ty, MangledName, FD);
+
   // Lookup the entry, lazily creating it if necessary.
   llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
   if (Entry) {
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -3929,6 +3929,29 @@
 
   void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);
 
+  struct MultiVersionResolverOption {
+    llvm::Function *Function;
+    TargetAttr::ParsedTargetAttr ParsedAttribute;
+    unsigned Priority;
+    MultiVersionResolverOption(const TargetInfo &TargInfo, llvm::Function *F,
+                               const clang::TargetAttr::ParsedTargetAttr &PT)
+        : Function(F), ParsedAttribute(PT), Priority(0u) {
+      for (StringRef Feat : PT.Features)
+        Priority = std::max(Priority,
+                            TargInfo.multiVersionSortPriority(Feat.substr(1)));
+
+      if (!PT.Architecture.empty())
+        Priority = std::max(Priority,
+                            TargInfo.multiVersionSortPriority(PT.Architecture));
+    }
+
+    bool operator>(const MultiVersionResolverOption &Other) const {
+      return Priority > Other.Priority;
+    }
+  };
+  void EmitMultiVersionResolver(llvm::Function *Resolver,
+                                ArrayRef<MultiVersionResolverOption> Options);
+
 private:
   QualType getVarArgType(const Expr *Arg);
 
@@ -3944,7 +3967,8 @@
   llvm::Value *EmitX86CpuIs(StringRef CPUStr);
   llvm::Value *EmitX86CpuSupports(const CallExpr *E);
   llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs);
-  llvm::Value *EmitX86CpuInit();
+  llvm::Value *EmitX86CpuInit(CGBuilderTy &Builder);
+  llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO);
 };
 
 /// Helper class with most of the code for saving a value for a
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -2296,6 +2296,60 @@
   CGM.getSanStats().create(IRB, SSK);
 }
 
+llvm::Value *
+CodeGenFunction::FormResolverCondition(const MultiVersionResolverOption &RO) {
+  llvm::Value *TrueCondition = nullptr;
+  if (!RO.ParsedAttribute.Architecture.empty())
+    TrueCondition = EmitX86CpuIs(RO.ParsedAttribute.Architecture);
+
+  if (!RO.ParsedAttribute.Features.empty()) {
+    SmallVector<StringRef, 8> FeatureList;
+    llvm::for_each(RO.ParsedAttribute.Features,
+                   [&FeatureList](const std::string &Feature) {
+                     FeatureList.push_back(StringRef{Feature}.substr(1));
+                   });
+    llvm::Value *FeatureCmp = EmitX86CpuSupports(FeatureList);
+    TrueCondition = TrueCondition ? Builder.CreateAnd(TrueCondition, FeatureCmp)
+                                  : FeatureCmp;
+  }
+  return TrueCondition;
+}
+
+void CodeGenFunction::EmitMultiVersionResolver(
+    llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
+  assert((getContext().getTargetInfo().getTriple().getArch() ==
+              llvm::Triple::x86 ||
+          getContext().getTargetInfo().getTriple().getArch() ==
+              llvm::Triple::x86_64) &&
+         "Only implemented for x86 targets");
+
+  // Main function's basic block.
+  llvm::BasicBlock *CurBlock = createBasicBlock("entry", Resolver);
+  Builder.SetInsertPoint(CurBlock);
+  EmitX86CpuInit(Builder);
+
+  llvm::Function *DefaultFunc = nullptr;
+  for (const MultiVersionResolverOption &RO : Options) {
+    Builder.SetInsertPoint(CurBlock);
+    llvm::Value *TrueCondition = FormResolverCondition(RO);
+
+    if (!TrueCondition) {
+      DefaultFunc = RO.Function;
+    } else {
+      llvm::BasicBlock *RetBlock = createBasicBlock("ro_ret", Resolver);
+      llvm::IRBuilder<> RetBuilder(RetBlock);
+      RetBuilder.CreateRet(RO.Function);
+      CurBlock = createBasicBlock("ro_else", Resolver);
+      Builder.CreateCondBr(TrueCondition, RetBlock, CurBlock);
+    }
+  }
+
+  assert(DefaultFunc && "No default version?");
+  // Emit return from the 'else-ist' block.
+  Builder.SetInsertPoint(CurBlock);
+  Builder.CreateRet(DefaultFunc);
+}
+
 llvm::DebugLoc CodeGenFunction::SourceLocToDebugLoc(SourceLocation Location) {
   if (CGDebugInfo *DI = getDebugInfo())
     return DI->SourceLocToDebugLoc(Location);
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -7670,7 +7670,7 @@
   return Builder.CreateICmpNE(Bitset, llvm::ConstantInt::get(Int32Ty, 0));
 }
 
-Value *CodeGenFunction::EmitX86CpuInit() {
+Value *CodeGenFunction::EmitX86CpuInit(CGBuilderTy &Builder) {
   llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
                                                     /*Variadic*/ false);
   llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, "__cpu_indicator_init");
@@ -7684,7 +7684,7 @@
   if (BuiltinID == X86::BI__builtin_cpu_supports)
     return EmitX86CpuSupports(E);
   if (BuiltinID == X86::BI__builtin_cpu_init)
-    return EmitX86CpuInit();
+    return EmitX86CpuInit(Builder);
 
   SmallVector<Value*, 4> Ops;
 
Index: lib/Basic/Targets/X86.h
===================================================================
--- lib/Basic/Targets/X86.h
+++ lib/Basic/Targets/X86.h
@@ -105,6 +105,8 @@
 
   CPUKind getCPUKind(StringRef CPU) const;
 
+  std::string getCPUKindCanonicalName(CPUKind Kind) const;
+
   enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default;
 
 public:
@@ -246,6 +248,11 @@
     return checkCPUKind(CPU = getCPUKind(Name));
   }
 
+  bool supportsMultiVersioning() const override {
+    return getTriple().isOSBinFormatELF();
+  }
+  unsigned multiVersionSortPriority(StringRef Name) const override;
+
   bool setFPMath(StringRef Name) override;
 
   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
Index: lib/Basic/Targets/X86.cpp
===================================================================
--- lib/Basic/Targets/X86.cpp
+++ lib/Basic/Targets/X86.cpp
@@ -17,6 +17,7 @@
 #include "clang/Basic/TargetBuiltins.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/TargetParser.h"
 
 namespace clang {
 namespace targets {
@@ -1264,6 +1265,63 @@
       .Default(false);
 }
 
+static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
+  return llvm::StringSwitch<llvm::X86::ProcessorFeatures>(Name)
+#define X86_FEATURE_COMPAT(VAL, ENUM, STR) .Case(STR, llvm::X86::ENUM)
+#include "llvm/Support/X86TargetParser.def"
+      ;
+  // Note, this function should only be used after ensuring the value is
+  // correct, so it asserts if the value is out of range.
+}
+
+static unsigned getFeaturePriority(llvm::X86::ProcessorFeatures Feat) {
+  enum class FeatPriority {
+#define FEATURE(FEAT) FEAT,
+#include "clang/Basic/X86Target.def"
+  };
+  switch (Feat) {
+#define FEATURE(FEAT)                                                          \
+  case llvm::X86::FEAT:                                                        \
+    return static_cast<unsigned>(FeatPriority::FEAT);
+#include "clang/Basic/X86Target.def"
+  default:
+    llvm_unreachable("No Feature Priority for non-CPUSupports Features");
+  }
+}
+
+unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const {
+  // Valid CPUs have a 'key feature' that compares just better than its key
+  // feature.
+  CPUKind Kind = getCPUKind(Name);
+  if (Kind != CK_Generic) {
+    switch (Kind) {
+    default:
+      llvm_unreachable(
+          "CPU Type without a key feature used in 'target' attribute");
+#define PROC_WITH_FEAT(ENUM, STR, IS64, KEY_FEAT)                              \
+  case CK_##ENUM:                                                              \
+    return (getFeaturePriority(llvm::X86::KEY_FEAT) << 1) + 1;
+#include "clang/Basic/X86Target.def"
+    }
+  }
+
+  // Now we know we have a feature, so get its priority and shift it a few so
+  // that we have sufficient room for the CPUs (above).
+  return getFeaturePriority(getFeature(Name)) << 1;
+}
+
+std::string X86TargetInfo::getCPUKindCanonicalName(CPUKind Kind) const {
+  switch (Kind) {
+  case CK_Generic:
+    return "";
+#define PROC(ENUM, STRING, IS64BIT)                                            \
+  case CK_##ENUM:                                                              \
+    return STRING;
+#include "clang/Basic/X86Target.def"
+  }
+  llvm_unreachable("Invalid CPUKind");
+}
+
 // We can't use a generic validation scheme for the cpus accepted here
 // versus subtarget cpus accepted in the target attribute because the
 // variables intitialized by the runtime only support the below currently
Index: include/clang/Sema/Overload.h
===================================================================
--- include/clang/Sema/Overload.h
+++ include/clang/Sema/Overload.h
@@ -613,6 +613,10 @@
     /// This inherited constructor is not viable because it would slice the
     /// argument.
     ovl_fail_inhctor_slice,
+
+    /// This candidate was not viable because it is a non-default multiversioned
+    /// function.
+    ovl_non_default_multiversion_function,
   };
 
   /// A list of implicit conversion sequences for the arguments of an
Index: include/clang/Basic/X86Target.def
===================================================================
--- include/clang/Basic/X86Target.def
+++ include/clang/Basic/X86Target.def
@@ -12,6 +12,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#ifndef PROC_WITH_FEAT
+#define PROC_WITH_FEAT(ENUM, STRING, IS64BIT, KEYFEATURE)                      \
+  PROC(ENUM, STRING, IS64BIT)
+#endif
 
 #ifndef PROC
 #define PROC(ENUM, STRING, IS64BIT)
@@ -21,6 +25,10 @@
 #define PROC_ALIAS(ENUM, ALIAS)
 #endif
 
+#ifndef FEATURE
+#define FEATURE(ENUM)
+#endif
+
 #define PROC_64_BIT true
 #define PROC_32_BIT false
 
@@ -77,7 +85,7 @@
 /// \name Core
 /// Core microarchitecture based processors.
 //@{
-PROC(Core2, "core2", PROC_64_BIT)
+PROC_WITH_FEAT(Core2, "core2", PROC_64_BIT, FEATURE_SSSE3)
 
 /// This enumerator, like Yonah, is a bit odd. It is another
 /// codename which GCC no longer accepts as an option to -march, but Clang
@@ -89,67 +97,67 @@
 /// \name Atom
 /// Atom processors
 //@{
-PROC(Bonnell, "bonnell", PROC_64_BIT)
+PROC_WITH_FEAT(Bonnell, "bonnell", PROC_64_BIT, FEATURE_SSSE3)
 PROC_ALIAS(Bonnell, "atom")
 
-PROC(Silvermont, "silvermont", PROC_64_BIT)
+PROC_WITH_FEAT(Silvermont, "silvermont", PROC_64_BIT, FEATURE_SSE4_2)
 PROC_ALIAS(Silvermont, "slm")
 
 PROC(Goldmont, "goldmont", PROC_64_BIT)
 //@}
 
 /// \name Nehalem
 /// Nehalem microarchitecture based processors.
-PROC(Nehalem, "nehalem", PROC_64_BIT)
+PROC_WITH_FEAT(Nehalem, "nehalem", PROC_64_BIT, FEATURE_SSE4_2)
 PROC_ALIAS(Nehalem, "corei7")
 
 /// \name Westmere
 /// Westmere microarchitecture based processors.
-PROC(Westmere, "westmere", PROC_64_BIT)
+PROC_WITH_FEAT(Westmere, "westmere", PROC_64_BIT, FEATURE_PCLMUL)
 
 /// \name Sandy Bridge
 /// Sandy Bridge microarchitecture based processors.
-PROC(SandyBridge, "sandybridge", PROC_64_BIT)
+PROC_WITH_FEAT(SandyBridge, "sandybridge", PROC_64_BIT, FEATURE_AVX)
 PROC_ALIAS(SandyBridge, "corei7-avx")
 
 /// \name Ivy Bridge
 /// Ivy Bridge microarchitecture based processors.
-PROC(IvyBridge, "ivybridge", PROC_64_BIT)
+PROC_WITH_FEAT(IvyBridge, "ivybridge", PROC_64_BIT, FEATURE_AVX)
 PROC_ALIAS(IvyBridge, "core-avx-i")
 
 /// \name Haswell
 /// Haswell microarchitecture based processors.
-PROC(Haswell, "haswell", PROC_64_BIT)
+PROC_WITH_FEAT(Haswell, "haswell", PROC_64_BIT, FEATURE_AVX2)
 PROC_ALIAS(Haswell, "core-avx2")
 
 /// \name Broadwell
 /// Broadwell microarchitecture based processors.
-PROC(Broadwell, "broadwell", PROC_64_BIT)
+PROC_WITH_FEAT(Broadwell, "broadwell", PROC_64_BIT, FEATURE_AVX2)
 
 /// \name Skylake Client
 /// Skylake client microarchitecture based processors.
-PROC(SkylakeClient, "skylake", PROC_64_BIT)
+PROC_WITH_FEAT(SkylakeClient, "skylake", PROC_64_BIT, FEATURE_AVX2)
 
 /// \name Skylake Server
 /// Skylake server microarchitecture based processors.
-PROC(SkylakeServer, "skylake-avx512", PROC_64_BIT)
+PROC_WITH_FEAT(SkylakeServer, "skylake-avx512", PROC_64_BIT, FEATURE_AVX512F)
 PROC_ALIAS(SkylakeServer, "skx")
 
 /// \name Cannonlake Client
 /// Cannonlake client microarchitecture based processors.
-PROC(Cannonlake, "cannonlake", PROC_64_BIT)
+PROC_WITH_FEAT(Cannonlake, "cannonlake", PROC_64_BIT, FEATURE_AVX512VBMI)
 
 /// \name Icelake Client
 /// Icelake client microarchitecture based processors.
 PROC(Icelake, "icelake", PROC_64_BIT)
 
 /// \name Knights Landing
 /// Knights Landing processor.
-PROC(KNL, "knl", PROC_64_BIT)
+PROC_WITH_FEAT(KNL, "knl", PROC_64_BIT, FEATURE_AVX512F)
 
 /// \name Knights Mill
 /// Knights Mill processor.
-PROC(KNM, "knm", PROC_64_BIT)
+PROC_WITH_FEAT(KNM, "knm", PROC_64_BIT, FEATURE_AVX5124FMAPS)
 
 /// \name Lakemont
 /// Lakemont microarchitecture based processors.
@@ -186,30 +194,30 @@
 PROC_ALIAS(K8SSE3, "athlon64-sse3")
 PROC_ALIAS(K8SSE3, "opteron-sse3")
 
-PROC(AMDFAM10, "amdfam10", PROC_64_BIT)
+PROC_WITH_FEAT(AMDFAM10, "amdfam10", PROC_64_BIT, FEATURE_SSE4_A)
 PROC_ALIAS(AMDFAM10, "barcelona")
 //@}
 
 /// \name Bobcat
 /// Bobcat architecture processors.
 //@{
-PROC(BTVER1, "btver1", PROC_64_BIT)
-PROC(BTVER2, "btver2", PROC_64_BIT)
+PROC_WITH_FEAT(BTVER1, "btver1", PROC_64_BIT, FEATURE_SSE4_A)
+PROC_WITH_FEAT(BTVER2, "btver2", PROC_64_BIT, FEATURE_BMI)
 //@}
 
 /// \name Bulldozer
 /// Bulldozer architecture processors.
 //@{
-PROC(BDVER1, "bdver1", PROC_64_BIT)
-PROC(BDVER2, "bdver2", PROC_64_BIT)
-PROC(BDVER3, "bdver3", PROC_64_BIT)
-PROC(BDVER4, "bdver4", PROC_64_BIT)
+PROC_WITH_FEAT(BDVER1, "bdver1", PROC_64_BIT, FEATURE_XOP)
+PROC_WITH_FEAT(BDVER2, "bdver2", PROC_64_BIT, FEATURE_FMA)
+PROC_WITH_FEAT(BDVER3, "bdver3", PROC_64_BIT, FEATURE_FMA)
+PROC_WITH_FEAT(BDVER4, "bdver4", PROC_64_BIT, FEATURE_AVX2)
 //@}
 
 /// \name zen
 /// Zen architecture processors.
 //@{
-PROC(ZNVER1, "znver1", PROC_64_BIT)
+PROC_WITH_FEAT(ZNVER1, "znver1", PROC_64_BIT, FEATURE_AVX2)
 //@}
 
 /// This specification is deprecated and will be removed in the future.
@@ -225,8 +233,45 @@
 PROC(Geode, "geode", PROC_32_BIT)
 //@}
 
+// List of CPU Supports features in order.  These need to remain in the order
+// required by attribute 'target' checking.  Note that not all are supported/
+// prioritized by GCC, so synchronization with GCC's implementation may require
+// changing some existing values.
+FEATURE(FEATURE_CMOV)
+FEATURE(FEATURE_MMX)
+FEATURE(FEATURE_SSE)
+FEATURE(FEATURE_SSE2)
+FEATURE(FEATURE_SSE3)
+FEATURE(FEATURE_SSSE3)
+FEATURE(FEATURE_SSE4_A)
+FEATURE(FEATURE_SSE4_1)
+FEATURE(FEATURE_SSE4_2)
+FEATURE(FEATURE_POPCNT)
+FEATURE(FEATURE_AES)
+FEATURE(FEATURE_PCLMUL)
+FEATURE(FEATURE_AVX)
+FEATURE(FEATURE_BMI)
+FEATURE(FEATURE_FMA4)
+FEATURE(FEATURE_XOP)
+FEATURE(FEATURE_FMA)
+FEATURE(FEATURE_BMI2)
+FEATURE(FEATURE_AVX2)
+FEATURE(FEATURE_AVX512F)
+FEATURE(FEATURE_AVX512VL)
+FEATURE(FEATURE_AVX512BW)
+FEATURE(FEATURE_AVX512DQ)
+FEATURE(FEATURE_AVX512CD)
+FEATURE(FEATURE_AVX512ER)
+FEATURE(FEATURE_AVX512PF)
+FEATURE(FEATURE_AVX512VBMI)
+FEATURE(FEATURE_AVX512IFMA)
+FEATURE(FEATURE_AVX5124VNNIW)
+FEATURE(FEATURE_AVX5124FMAPS)
+FEATURE(FEATURE_AVX512VPOPCNTDQ)
 
 #undef PROC_64_BIT
 #undef PROC_32_BIT
+#undef FEATURE
 #undef PROC
 #undef PROC_ALIAS
+#undef PROC_WITH_FEAT
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -912,10 +912,20 @@
     return false;
   }
 
+  /// \brief Identify whether this taret supports multiversioning of functions,
+  /// which requires support for cpu_supports and cpu_is functionality.
+  virtual bool supportsMultiVersioning() const { return false; }
+
   // \brief Validate the contents of the __builtin_cpu_supports(const char*)
   // argument.
   virtual bool validateCpuSupports(StringRef Name) const { return false; }
 
+  // \brief Return the target-specific priority for features/cpus/vendors so
+  // that they can be properly sorted for checking.
+  virtual unsigned multiVersionSortPriority(StringRef Name) const {
+    return 0;
+  }
+
   // \brief Validate the contents of the __builtin_cpu_is(const char*)
   // argument.
   virtual bool validateCpuIs(StringRef Name) const { return false; }
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -9315,4 +9315,37 @@
   InGroup<ShadowField>, DefaultIgnore;
 def note_shadow_field : Note<"declared here">;
 
+def err_target_required_in_redecl : Error<
+  "function declaration is missing 'target' attribute in a multiversioned "
+  "function">;
+def note_multiversioning_caused_here : Note<
+  "function multiversion caused by this declaration">;
+def err_multiversion_after_used : Error<
+  "function declaration cannot become a multiversioned function after first "
+  "usage">;
+def err_bad_multiversion_option : Error<
+  "function multiversioning doesn't support %select{feature|architecture}0 "
+  "'%1'">;
+def note_ovl_candidate_nondefault_multiversion : Note<
+  "candidate ignored: non-default multiversion function cannot be called "
+  "directly">;
+def err_multiversion_duplicate : Error<
+  "multiversion function redeclarations require identical target attributes">;
+def err_multiversion_noproto : Error<
+  "multiversion function must have a prototype">;
+def err_multiversion_no_other_attrs : Error<
+  "attribute 'target' multiversioning cannot be combined with other "
+  "attributes">;
+def err_multiversion_diff : Error<
+  "multiversion function declaration has a different %select{calling convention"
+  "|return type|constexpr specification|inline specification|storage class|"
+  "linkage}0">;
+def err_multiversion_doesnt_support : Error<
+  "multiversion functions do not yet support %select{function templates|"
+  "virtual functions|deduced return types}0">;
+def err_multiversion_not_allowed_on_main : Error<
+  "'main' cannot be a multiversion function">;
+def err_multiversion_not_supported : Error<
+ "function multiversioning is not supported on the current target">;
+
 } // end of sema component.
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1806,12 +1806,25 @@
       std::vector<std::string> Features;
       StringRef Architecture;
       bool DuplicateArchitecture = false;
+      bool operator==(const ParsedTargetAttr &Other) const{
+        return DuplicateArchitecture == Other.DuplicateArchitecture &&
+               Architecture == Other.Architecture && Features == Other.Features;
+      }
     };
     ParsedTargetAttr parse() const {
       return parse(getFeaturesStr());
     }
+
+    template<class Compare>
+    ParsedTargetAttr parse(Compare cmp) const {
+      ParsedTargetAttr Attrs = parse();
+      std::sort(std::begin(Attrs.Features), std::end(Attrs.Features), cmp);
+      return Attrs;
+    }
+
     static ParsedTargetAttr parse(StringRef Features) {
       ParsedTargetAttr Ret;
+      if (Features == "default") return Ret;
       SmallVector<StringRef, 1> AttrFeatures;
       Features.split(AttrFeatures, ",");
 
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1751,6 +1751,10 @@
   /// parsing it.
   unsigned WillHaveBody : 1;
 
+  /// Indicates that this function is a multiversioned function using attribute
+  /// 'target'.
+  unsigned IsMultiVersion : 1;
+
 protected:
   /// [C++17] Only used by CXXDeductionGuideDecl. Declared here to avoid
   /// increasing the size of CXXDeductionGuideDecl by the size of an unsigned
@@ -1842,8 +1846,9 @@
         IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
         IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
         InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false),
-        WillHaveBody(false), IsCopyDeductionCandidate(false),
-        EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {}
+        WillHaveBody(false), IsMultiVersion(false),
+        IsCopyDeductionCandidate(false), EndRangeLoc(NameInfo.getEndLoc()),
+        DNLoc(NameInfo.getInfo()) {}
 
   using redeclarable_base = Redeclarable<FunctionDecl>;
 
@@ -2151,6 +2156,17 @@
   bool willHaveBody() const { return WillHaveBody; }
   void setWillHaveBody(bool V = true) { WillHaveBody = V; }
 
+  /// True if this function is considered a multiversioned function.
+  bool isMultiVersion() const { return IsMultiVersion; }
+
+  /// Sets the multiversion state for this declaration and all of its
+  /// redeclarations.
+  void setIsMultiVersion(bool V = true) {
+    IsMultiVersion = V;
+    for (FunctionDecl *FD : redecls())
+      FD->IsMultiVersion = V;
+  }
+
   void setPreviousDeclaration(FunctionDecl * PrevDecl);
 
   FunctionDecl *getCanonicalDecl() override;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to