summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/Decl.h4
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp60
-rw-r--r--clang/lib/CodeGen/CGValue.h17
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h3
-rw-r--r--clang/lib/Sema/SemaDecl.cpp15
-rw-r--r--clang/test/CodeGen/named_reg_global.c26
-rw-r--r--clang/test/Sema/asm.c2
-rw-r--r--clang/test/Sema/decl-invalid.c1
8 files changed, 115 insertions, 13 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 3618fa417be..f6547910038 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -826,6 +826,10 @@ public:
// Second check is for C++11 [dcl.stc]p4.
return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
+ // Global Named Register (GNU extension)
+ if (getStorageClass() == SC_Register && !isLocalVarDecl())
+ return false;
+
// Return true for: Auto, Register.
// Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal.
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 2be47b46e22..4822769f392 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -21,6 +21,7 @@
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/IR/DataLayout.h"
@@ -1276,6 +1277,10 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
if (LV.isExtVectorElt())
return EmitLoadOfExtVectorElementLValue(LV);
+ // Global Register variables always invoke intrinsics
+ if (LV.isGlobalReg())
+ return EmitLoadOfGlobalRegLValue(LV);
+
assert(LV.isBitField() && "Unknown LValue type!");
return EmitLoadOfBitfieldLValue(LV);
}
@@ -1343,6 +1348,16 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
return RValue::get(Vec);
}
+/// @brief Load of global gamed gegisters are always calls to intrinsics.
+RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
+ assert(LV.getType()->isIntegerType() && "Bad type for register variable");
+ llvm::MDNode *RegName = dyn_cast<llvm::MDNode>(LV.getGlobalReg());
+ assert(RegName && "Register LValue is not metadata");
+ llvm::Type *Types[] = { CGM.getTypes().ConvertType(LV.getType()) };
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
+ llvm::Value* Call = Builder.CreateCall(F, RegName);
+ return RValue::get(Call);
+}
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
@@ -1370,6 +1385,9 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
if (Dst.isExtVectorElt())
return EmitStoreThroughExtVectorComponentLValue(Src, Dst);
+ if (Dst.isGlobalReg())
+ return EmitStoreThroughGlobalRegLValue(Src, Dst);
+
assert(Dst.isBitField() && "Unknown LValue type");
return EmitStoreThroughBitfieldLValue(Src, Dst);
}
@@ -1581,6 +1599,17 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
Store->setAlignment(Dst.getAlignment().getQuantity());
}
+/// @brief Store of global named registers are always calls to intrinsics.
+void CodeGenFunction::EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst) {
+ assert(Dst.getType()->isIntegerType() && "Bad type for register variable");
+ llvm::MDNode *RegName = dyn_cast<llvm::MDNode>(Dst.getGlobalReg());
+ assert(RegName && "Register LValue is not metadata");
+ llvm::Type *Types[] = { CGM.getTypes().ConvertType(Dst.getType()) };
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
+ llvm::Value *Value = Src.getScalarVal();
+ Builder.CreateCall2(F, RegName, Value);
+}
+
// setObjCGCLValueClass - sets class of he lvalue for the purpose of
// generating write-barries API. It is currently a global, ivar,
// or neither.
@@ -1740,14 +1769,41 @@ static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
return CGF.EmitLValueForField(LV, FD);
}
+/// Named Registers are named metadata pointing to the register name
+/// which will be read from/written to as an argument to the intrinsic
+/// @llvm.read/write_register.
+/// So far, only the name is being passed down, but other options such as
+/// register type, allocation type or even optimization options could be
+/// passed down via the metadata node.
+static LValue EmitGlobalNamedRegister(const VarDecl *VD,
+ CodeGenModule &CGM,
+ CharUnits Alignment) {
+ AsmLabelAttr *Asm = VD->getAttr<AsmLabelAttr>();
+ llvm::Twine Name("llvm.named.register."+Asm->getLabel());
+ llvm::NamedMDNode *M = CGM.getModule().getOrInsertNamedMetadata(Name.str());
+ if (M->getNumOperands() == 0) {
+ llvm::MDString *Str = llvm::MDString::get(CGM.getLLVMContext(),
+ Asm->getLabel());
+ llvm::Value *Ops[] = { Str };
+ M->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
+ }
+ return LValue::MakeGlobalReg(M->getOperand(0), VD->getType(), Alignment);
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
const NamedDecl *ND = E->getDecl();
CharUnits Alignment = getContext().getDeclAlign(ND);
QualType T = E->getType();
+ const auto *VD = dyn_cast<VarDecl>(ND);
+
+ // Global Named registers access via intrinsics only
+ if (VD && VD->getStorageClass() == SC_Register &&
+ VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())
+ return EmitGlobalNamedRegister(VD, CGM, Alignment);
// A DeclRefExpr for a reference initialized by a constant expression can
// appear without being odr-used. Directly emit the constant initializer.
- if (const auto *VD = dyn_cast<VarDecl>(ND)) {
+ if (VD) {
const Expr *Init = VD->getAnyInitializer(VD);
if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
VD->isUsableInConstantExpressions(getContext()) &&
@@ -1773,7 +1829,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return MakeAddrLValue(Aliasee, T, Alignment);
}
- if (const auto *VD = dyn_cast<VarDecl>(ND)) {
+ if (VD) {
// Check if this is a global variable.
if (VD->hasLinkage() || VD->isStaticDataMember())
return EmitGlobalVarDeclLValue(*this, E, VD);
diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h
index da2a03437d3..3739ae95509 100644
--- a/clang/lib/CodeGen/CGValue.h
+++ b/clang/lib/CodeGen/CGValue.h
@@ -110,7 +110,8 @@ class LValue {
Simple, // This is a normal l-value, use getAddress().
VectorElt, // This is a vector element l-value (V[i]), use getVector*
BitField, // This is a bitfield l-value, use getBitfield*.
- ExtVectorElt // This is an extended vector subset, use getExtVectorComp
+ ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
+ GlobalReg // This is a register l-value, use getGlobalReg()
} LVType;
llvm::Value *V;
@@ -192,6 +193,7 @@ public:
bool isVectorElt() const { return LVType == VectorElt; }
bool isBitField() const { return LVType == BitField; }
bool isExtVectorElt() const { return LVType == ExtVectorElt; }
+ bool isGlobalReg() const { return LVType == GlobalReg; }
bool isVolatileQualified() const { return Quals.hasVolatile(); }
bool isRestrictQualified() const { return Quals.hasRestrict(); }
@@ -286,6 +288,9 @@ public:
return *BitFieldInfo;
}
+ // global register lvalue
+ llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; }
+
static LValue MakeAddr(llvm::Value *address, QualType type,
CharUnits alignment, ASTContext &Context,
llvm::MDNode *TBAAInfo = 0) {
@@ -336,6 +341,16 @@ public:
return R;
}
+ static LValue MakeGlobalReg(llvm::Value *Reg,
+ QualType type,
+ CharUnits Alignment) {
+ LValue R;
+ R.LVType = GlobalReg;
+ R.V = Reg;
+ R.Initialize(type, type.getQualifiers(), Alignment);
+ return R;
+ }
+
RValue asAggregateRValue() const {
// FIMXE: Alignment
return RValue::getAggregate(getAddress(), isVolatileQualified());
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 6af7a98d96e..c859ddab773 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1979,12 +1979,14 @@ public:
RValue EmitLoadOfLValue(LValue V, SourceLocation Loc);
RValue EmitLoadOfExtVectorElementLValue(LValue V);
RValue EmitLoadOfBitfieldLValue(LValue LV);
+ RValue EmitLoadOfGlobalRegLValue(LValue LV);
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
/// lvalue, where both are guaranteed to the have the same type, and that type
/// is 'Ty'.
void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false);
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
+ void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst);
/// EmitStoreThroughBitfieldLValue - Store Src into Dst with same constraints
/// as EmitStoreThroughLValue.
@@ -2009,6 +2011,7 @@ public:
// Note: only available for agg return types
LValue EmitVAArgExprLValue(const VAArgExpr *E);
LValue EmitDeclRefLValue(const DeclRefExpr *E);
+ LValue EmitReadRegister(const VarDecl *VD);
LValue EmitStringLiteralLValue(const StringLiteral *E);
LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E);
LValue EmitPredefinedLValue(const PredefinedExpr *E);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3c19e9632f6..5276cafcf72 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5119,13 +5119,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!DC->isRecord() && S->getFnParent() == 0) {
// C99 6.9p2: The storage-class specifiers auto and register shall not
// appear in the declaration specifiers in an external declaration.
- if (SC == SC_Auto || SC == SC_Register) {
- // If this is a register variable with an asm label specified, then this
- // is a GNU extension.
- if (SC == SC_Register && D.getAsmLabel())
- Diag(D.getIdentifierLoc(), diag::err_unsupported_global_register);
- else
- Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope);
+ // Global Register+Asm is a GNU extension we support.
+ if (SC == SC_Auto || (SC == SC_Register && !D.getAsmLabel())) {
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope);
D.setInvalidType();
}
}
@@ -5437,6 +5433,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label;
break;
case SC_Register:
+ // Local Named register
if (!Context.getTargetInfo().isValidGCCRegisterName(Label))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
break;
@@ -5446,6 +5443,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
case SC_OpenCLWorkGroupLocal:
break;
}
+ } else if (SC == SC_Register) {
+ // Global Named register
+ if (!Context.getTargetInfo().isValidGCCRegisterName(Label))
+ Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
}
NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0),
diff --git a/clang/test/CodeGen/named_reg_global.c b/clang/test/CodeGen/named_reg_global.c
new file mode 100644
index 00000000000..0a4646f7bdb
--- /dev/null
+++ b/clang/test/CodeGen/named_reg_global.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
+
+register unsigned long current_stack_pointer asm("sp");
+
+// CHECK: define{{.*}} i[[bits:[0-9]+]] @get_stack_pointer_addr()
+// CHECK: [[ret:%[0-9]+]] = call i[[bits]] @llvm.read_register.i[[bits]](metadata !0)
+// CHECK: ret i[[bits]] [[ret]]
+unsigned long get_stack_pointer_addr() {
+ return current_stack_pointer;
+}
+// CHECK: declare{{.*}} i[[bits]] @llvm.read_register.i[[bits]](metadata)
+
+// CHECK: define{{.*}} void @set_stack_pointer_addr(i[[bits]] %addr) #0 {
+// CHECK: [[sto:%[0-9]+]] = load i[[bits]]* %addr
+// CHECK: call void @llvm.write_register.i[[bits]](metadata !0, i[[bits]] [[sto]])
+// CHECK: ret void
+void set_stack_pointer_addr(unsigned long addr) {
+ current_stack_pointer = addr;
+}
+// CHECK: declare{{.*}} void @llvm.write_register.i[[bits]](metadata, i[[bits]])
+
+// CHECK: !llvm.named.register.sp = !{!0}
+// CHECK: !0 = metadata !{metadata !"sp"}
diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c
index 1559b228c87..4d84afce765 100644
--- a/clang/test/Sema/asm.c
+++ b/clang/test/Sema/asm.c
@@ -95,8 +95,6 @@ void test9(int i) {
asm("" : [foo] "=r" (i), "=r"(i) : "[foo]1"(i)); // expected-error{{invalid input constraint '[foo]1' in asm}}
}
-register int g asm("dx"); // expected-error{{global register variables are not supported}}
-
void test10(void){
static int g asm ("g_asm") = 0;
extern int gg asm ("gg_asm");
diff --git a/clang/test/Sema/decl-invalid.c b/clang/test/Sema/decl-invalid.c
index 0544304c20e..c7ec6dd725d 100644
--- a/clang/test/Sema/decl-invalid.c
+++ b/clang/test/Sema/decl-invalid.c
@@ -24,5 +24,4 @@ I; // expected-warning {{declaration does not declare anything}}
// rdar://6880449
register int test1; // expected-error {{illegal storage class on file-scoped variable}}
-register int test2 __asm__("edi"); // expected-error {{global register variables are not supported}}
OpenPOWER on IntegriCloud