r209149 - Non-allocatable Global Named Register

Justin Bogner mail at justinbogner.com
Mon May 19 15:17:53 PDT 2014


It looks like the tests you've added here rely on having an asserts
build. Specifically:

> +// CHECK: [[sto:%[0-9]+]] = load i[[bits]]* %addr

the function this matches looks like so with asserts:

    define void @set_stack_pointer_addr(i64 %addr) #0 {
    entry:
      %addr.addr = alloca i64, align 8
      store i64 %addr, i64* %addr.addr, align 8
      %0 = load i64* %addr.addr, align 8
      call void @llvm.write_register.i64(metadata !0, i64 %0)
      ret void
    }

So we match here:

  %0 = load i64* %addr.addr, align 8

but in release, the line reads like so instead:

  %2 = load i64* %1, align 8

so the %addr doesn't match.

Would you mind taking a look?

Renato Golin <renato.golin at linaro.org> writes:
> Author: rengolin
> Date: Mon May 19 13:15:42 2014
> New Revision: 209149
>
> URL: http://llvm.org/viewvc/llvm-project?rev=209149&view=revLog:
> Non-allocatable Global Named Register
>
> This patch implements global named registers in Clang, lowering to the just
> created intrinsics in LLVM (@llvm.read/write_register). A new type of LValue
> had to be created (Register), which just adds support to carry the metadata
> node containing the name of the register. Two new methods to emit loads and
> stores interoperate with another to emit the named metadata node.
>
> No guarantees are being made and only non-allocatable global variable named
> registers are being supported. Local named register support is unchanged.
>
> Added:
>     cfe/trunk/test/CodeGen/named_reg_global.c
> Modified:
>     cfe/trunk/include/clang/AST/Decl.h
>     cfe/trunk/lib/CodeGen/CGExpr.cpp
>     cfe/trunk/lib/CodeGen/CGValue.h
>     cfe/trunk/lib/CodeGen/CodeGenFunction.h
>     cfe/trunk/lib/Sema/SemaDecl.cpp
>     cfe/trunk/test/Sema/asm.c
>     cfe/trunk/test/Sema/decl-invalid.c
>
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Mon May 19 13:15:42 2014
> @@ -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.
>  
>
> Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Mon May 19 13:15:42 2014
> @@ -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
>    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::EmitLoadOfExtVec
>    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::EmitStoreThroughLV
>      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::EmitStoreThroughEx
>    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(Co
>    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::EmitDeclRefLValu
>      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);
>
> Modified: cfe/trunk/lib/CodeGen/CGValue.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGValue.h?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/lib/CodeGen/CGValue.h (original)
> +++ cfe/trunk/lib/CodeGen/CGValue.h Mon May 19 13:15:42 2014
> @@ -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) {
> @@ -335,6 +340,16 @@ public:
>      R.Initialize(type, type.getQualifiers(), Alignment);
>      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
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon May 19 13:15:42 2014
> @@ -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);
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon May 19 13:15:42 2014
> @@ -5119,13 +5119,9 @@ Sema::ActOnVariableDeclarator(Scope *S,
>    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,
>          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,
>        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),
>
> Added: cfe/trunk/test/CodeGen/named_reg_global.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/named_reg_global.c?rev=209149&view=auto==============================================================================
> --- cfe/trunk/test/CodeGen/named_reg_global.c (added)
> +++ cfe/trunk/test/CodeGen/named_reg_global.c Mon May 19 13:15:42 2014
> @@ -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"}
>
> Modified: cfe/trunk/test/Sema/asm.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/asm.c?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/test/Sema/asm.c (original)
> +++ cfe/trunk/test/Sema/asm.c Mon May 19 13:15:42 2014
> @@ -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");
>
> Modified: cfe/trunk/test/Sema/decl-invalid.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/decl-invalid.c?rev=209149&r1=209148&r2=209149&view=diff==============================================================================
> --- cfe/trunk/test/Sema/decl-invalid.c (original)
> +++ cfe/trunk/test/Sema/decl-invalid.c Mon May 19 13:15:42 2014
> @@ -24,5 +24,4 @@ I; // expected-warning {{declaration doe
>  
>  // 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}}
>  
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list