[llvm-commits] [llvm-gcc-4.2] r112674 - in /llvm-gcc-4.2/trunk/gcc: llvm-convert.cpp llvm-internal.h

Dale Johannesen dalej at apple.com
Tue Aug 31 16:43:23 PDT 2010


Author: johannes
Date: Tue Aug 31 18:43:22 2010
New Revision: 112674

URL: http://llvm.org/viewvc/llvm-project?rev=112674&view=rev
Log:
Fix semantics of function-local asm "register" variables.
Handling of these was allowing the value of the variable
to be clobbered because the RAs allocated the register to
something else.  8305081.

Both gcc and llvm-gcc refer to "register variables", but that
is not really what they are.  The real requirements are much looser:
"Defining such a register variable does not reserve the register; it
remains available for other uses in places where flow control determines
the variable's value is not live.

This option does not guarantee that GCC will generate code that has this 
variable in the register you specify at all times. You may not code an 
explicit reference to this register in the assembler instruction template 
part of an asm statement and assume it will always refer to this variable. 
However, using the variable as an asm operand guarantees that the specified 
register is used for the operand."

So, we can just allocate the variable normally, and use magical asm
pixie dust to get its value into the right register around asm's (in
practice, it's done after all loads, in the hope that this will help
optimizations keep the value in the appropriate register all the time when
there are enough registers to do that - works in small examples anyway).
The RA need not be bothered at all.  Clang doesn't currently support this 
feature at all but it should be able to imitate what llvm-gcc generates easily.

The existing code is retained so handling of global asm register variables
doesn't crash; they don't work any better than before, though.


Modified:
    llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-internal.h

Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=112674&r1=112673&r2=112674&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Tue Aug 31 18:43:22 2010
@@ -2444,14 +2444,14 @@
 //                           ... Expressions ...
 //===----------------------------------------------------------------------===//
 
-static bool canEmitRegisterVariable(tree exp) {
+static bool canEmitLocalRegisterVariable(tree exp) {
   // Only variables can be marked as 'register'.
   if (TREE_CODE(exp) != VAR_DECL || !DECL_REGISTER(exp))
     return false;
 
-  // We can emit inline assembler for access to global register variables.
+  // Global register variables are not accepted here.
   if (TREE_STATIC(exp) || DECL_EXTERNAL(exp) || TREE_PUBLIC(exp))
-    return true;
+    return false;
 
   // Emit inline asm if this is local variable with assembler name on it.
   if (DECL_ASSEMBLER_NAME_SET_P(exp))
@@ -2461,6 +2461,19 @@
   return false;
 }
 
+static bool canEmitGlobalRegisterVariable(tree exp) {
+  // Only variables can be marked as 'register'.
+  if (TREE_CODE(exp) != VAR_DECL || !DECL_REGISTER(exp))
+    return false;
+
+  // Local register variables are not accepted here.
+  if (TREE_STATIC(exp) || DECL_EXTERNAL(exp) || TREE_PUBLIC(exp))
+    return true;
+
+  // Otherwise - it's normal automatic variable, or local register variable.
+  return false;
+}
+
 
 /// EmitLoadOfLValue - When an l-value expression is used in a context that
 /// requires an r-value, this method emits the lvalue computation, then loads
@@ -2478,10 +2491,10 @@
     DECL_GIMPLE_FORMAL_TEMP_P(exp) = 0;
     EmitAutomaticVariableDecl(exp);
     // Fall through.
-  } else if (canEmitRegisterVariable(exp)) {
-    // If this is a register variable, EmitLV can't handle it (there is no
-    // l-value of a register variable).  Emit an inline asm node that copies the
-    // value out of the specified register.
+  } else if (canEmitGlobalRegisterVariable(exp)) {
+    // If this is a global register variable, EmitLV can't handle it (there is
+    // no l-value of a global register variable).  Emit an inline asm node that
+    // copies the value out of the specified register.
     return EmitReadOfRegisterVariable(exp, DestLoc);
   }
 
@@ -2496,7 +2509,11 @@
       Value *Ptr = BitCastToType(LV.Ptr, Ty->getPointerTo());
       LoadInst *LI = Builder.CreateLoad(Ptr, isVolatile);
       LI->setAlignment(Alignment);
-      return LI;
+      if (canEmitLocalRegisterVariable(exp)) {
+        // For register variable, move the loaded variable into the right reg.
+        return EmitMoveOfRegVariableToRightReg(LI, exp);
+      } else
+        return LI;
     } else {
       EmitAggregateCopy(*DestLoc, MemRef(LV.Ptr, Alignment, isVolatile),
                         TREE_TYPE(exp));
@@ -3283,10 +3300,10 @@
     Builder.Insert(Cast);
     SET_DECL_LLVM(lhs, Cast);
     return Cast;
-  } else if (canEmitRegisterVariable(lhs)) {
-    // If this is a store to a register variable, EmitLV can't handle the dest
-    // (there is no l-value of a register variable).  Emit an inline asm node
-    // that copies the value into the specified register.
+  } else if (canEmitGlobalRegisterVariable(lhs)) {
+    // If this is a store to a global register variable, EmitLV can't handle the
+    // dest (there is no l-value of a global register variable).  Emit an inline
+    // asm node that copies the value into the specified register.
     Value *RHS = Emit(rhs, 0);
     RHS = CastToAnyType(RHS, RHSSigned, ConvertType(TREE_TYPE(lhs)), LHSSigned);
     EmitModifyOfRegisterVariable(lhs, RHS);
@@ -4301,8 +4318,8 @@
 #define LLVM_CANONICAL_ADDRESS_CONSTRAINTS "r"
 #endif
 
-/// Reads from register variables are handled by emitting an inline asm node
-/// that copies the value out of the specified register.
+ /// Reads from global register variables are handled by emitting an inline
+ /// asm node that copies the value out of the specified register.
 Value *TreeToLLVM::EmitReadOfRegisterVariable(tree decl,
                                               const MemRef *DestLoc) {
   const Type *Ty = ConvertType(TREE_TYPE(decl));
@@ -4327,8 +4344,43 @@
   return Call;
 }
 
-/// Stores to register variables are handled by emitting an inline asm node
-/// that copies the value into the specified register.
+/// Reads from register variables are handled by emitting an inline asm node
+/// that copies the value out of the specified register.
+Value *TreeToLLVM::EmitMoveOfRegVariableToRightReg(Instruction *I, tree var) {
+  // Create a 'call void asm sideeffect "", "{reg}"(Ty %RHS)'.
+  const Type *Ty = I->getType();
+
+  // If there was an error, return something bogus.
+  if (ValidateRegisterVariable(var)) {
+    if (Ty->isSingleValueType())
+      return UndefValue::get(Ty);
+    return 0;   // Just don't copy something into DestLoc.
+  }
+
+  std::vector<const Type*> ArgTys;
+  ArgTys.push_back(Ty);
+  FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), 
+                                        ArgTys, false);
+  const char *Name = extractRegisterName(var);
+  int RegNum = decode_reg_name(Name);
+  Name = LLVM_GET_REG_NAME(Name, RegNum);
+  InlineAsm *IA = InlineAsm::get(FTy, "", "{"+std::string(Name)+"}", 
+                                    true);
+  CallInst *Call = Builder.CreateCall(IA, I);
+  Call->setDoesNotThrow();
+  // Create another asm with the same reg, this time producing an output.
+  // Turn this into a 'tmp = call Ty asm "", "={reg}"()'.
+  FunctionType *FTy2 = FunctionType::get(Ty, std::vector<const Type*>(),
+                                        false);
+  InlineAsm *IA2 = InlineAsm::get(FTy2, "", "={"+std::string(Name)+"}",
+                                 true);
+  CallInst *Call2 = Builder.CreateCall(IA2);
+  Call2->setDoesNotThrow();
+  return Call2;
+}
+
+/// Stores to global register variables are handled by emitting an inline asm
+/// node that copies the value into the specified register.
 void TreeToLLVM::EmitModifyOfRegisterVariable(tree decl, Value *RHS) {
   // If there was an error, bail out.
   if (ValidateRegisterVariable(decl))

Modified: llvm-gcc-4.2/trunk/gcc/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-internal.h?rev=112674&r1=112673&r2=112674&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-internal.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-internal.h Tue Aug 31 18:43:22 2010
@@ -540,6 +540,7 @@
   Value *EmitASM_EXPR(tree_node *exp);
   Value *EmitReadOfRegisterVariable(tree_node *vardecl, const MemRef *DestLoc);
   void EmitModifyOfRegisterVariable(tree_node *vardecl, Value *RHS);
+  Value *EmitMoveOfRegVariableToRightReg(Instruction *I, tree_node *decl);
 
   // Helpers for Builtin Function Expansion.
   void EmitMemoryBarrier(bool ll, bool ls, bool sl, bool ss, bool device);





More information about the llvm-commits mailing list