[llvm] c142c06 - Place the BlockAddress type in the address space of the containing function

Alex Richardson via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 2 04:19:04 PDT 2021


Author: Alex Richardson
Date: 2021-07-02T12:17:55+01:00
New Revision: c142c06c19b3725f26f33652db098a2302586f22

URL: https://github.com/llvm/llvm-project/commit/c142c06c19b3725f26f33652db098a2302586f22
DIFF: https://github.com/llvm/llvm-project/commit/c142c06c19b3725f26f33652db098a2302586f22.diff

LOG: Place the BlockAddress type in the address space of the containing function

While this should not matter for most architectures (where the program
address space is 0), it is important for CHERI (and therefore Arm Morello).
We use address space 200 for all of our code pointers and without this
change we assert in the SelectionDAG handling of BlockAddress nodes.

It is also useful for AVR: previously programs targeting
AVR that attempt to read their own machine code
via a pointer to a label would instead read from RAM
using a pointer relative to the the start of program flash.

Reviewed By: dylanmckay, theraven
Differential Revision: https://reviews.llvm.org/D48803

Added: 
    llvm/test/Bitcode/blockaddress-addrspace.ll
    llvm/test/CodeGen/AVR/block-address-is-in-progmem-space.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/include/llvm/AsmParser/LLParser.h
    llvm/lib/AsmParser/LLParser.cpp
    llvm/lib/IR/Constants.cpp
    llvm/test/CodeGen/AVR/brind.ll

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 848ee2343b5e0..d87f791077e51 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4078,7 +4078,11 @@ Addresses of Basic Blocks
 ``blockaddress(@function, %block)``
 
 The '``blockaddress``' constant computes the address of the specified
-basic block in the specified function, and always has an ``i8*`` type.
+basic block in the specified function.
+
+It always has an ``i8 addrspace(P)*`` type, where ``P`` is the address space
+of the function containing ``%block`` (usually ``addrspace(0)``).
+
 Taking the address of the entry block is illegal.
 
 This value only has defined behavior when used as an operand to the

diff  --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 3981241bb2eee..8b26b65528972 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -507,7 +507,8 @@ namespace llvm {
                             PerFunctionState &PFS);
 
     // Constant Parsing.
-    bool parseValID(ValID &ID, PerFunctionState *PFS = nullptr);
+    bool parseValID(ValID &ID, PerFunctionState *PFS,
+                    Type *ExpectedTy = nullptr);
     bool parseGlobalValue(Type *Ty, Constant *&C);
     bool parseGlobalTypeAndValue(Constant *&V);
     bool parseGlobalValueVector(SmallVectorImpl<Constant *> &Elts,

diff  --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index f9f73d2a4ffd4..678bf822fe08e 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -970,7 +970,7 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
   } else {
     // The bitcast dest type is not present, it is implied by the dest type.
     ValID ID;
-    if (parseValID(ID))
+    if (parseValID(ID, /*PFS=*/nullptr))
       return true;
     if (ID.Kind != ValID::t_Constant)
       return error(AliaseeLoc, "invalid aliasee");
@@ -3321,7 +3321,7 @@ BasicBlock *LLParser::PerFunctionState::defineBB(const std::string &Name,
 /// sanity.  PFS is used to convert function-local operands of metadata (since
 /// metadata operands are not just parsed here but also converted to values).
 /// PFS can be null when we are not parsing metadata values inside a function.
-bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS) {
+bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
   ID.Loc = Lex.getLoc();
   switch (Lex.getKind()) {
   default:
@@ -3493,10 +3493,10 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS) {
     ValID Fn, Label;
 
     if (parseToken(lltok::lparen, "expected '(' in block address expression") ||
-        parseValID(Fn) ||
+        parseValID(Fn, PFS) ||
         parseToken(lltok::comma,
                    "expected comma in block address expression") ||
-        parseValID(Label) ||
+        parseValID(Label, PFS) ||
         parseToken(lltok::rparen, "expected ')' in block address expression"))
       return true;
 
@@ -3531,9 +3531,27 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS) {
                                               std::map<ValID, GlobalValue *>()))
               .first->second.insert(std::make_pair(std::move(Label), nullptr))
               .first->second;
-      if (!FwdRef)
-        FwdRef = new GlobalVariable(*M, Type::getInt8Ty(Context), false,
-                                    GlobalValue::InternalLinkage, nullptr, "");
+      if (!FwdRef) {
+        unsigned FwdDeclAS;
+        if (ExpectedTy) {
+          // If we know the type that the blockaddress is being assigned to,
+          // we can use the address space of that type.
+          if (!ExpectedTy->isPointerTy())
+            return error(ID.Loc,
+                         "type of blockaddress must be a pointer and not '" +
+                             getTypeString(ExpectedTy) + "'");
+          FwdDeclAS = ExpectedTy->getPointerAddressSpace();
+        } else if (PFS) {
+          // Otherwise, we default the address space of the current function.
+          FwdDeclAS = PFS->getFunction().getAddressSpace();
+        } else {
+          llvm_unreachable("Unknown address space for blockaddress");
+        }
+        FwdRef = new GlobalVariable(
+            *M, Type::getInt8Ty(Context), false, GlobalValue::InternalLinkage,
+            nullptr, "", nullptr, GlobalValue::NotThreadLocal, FwdDeclAS);
+      }
+
       ID.ConstantVal = FwdRef;
       ID.Kind = ValID::t_Constant;
       return false;
@@ -3570,7 +3588,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS) {
 
     ValID Fn;
 
-    if (parseValID(Fn))
+    if (parseValID(Fn, PFS))
       return true;
 
     if (Fn.Kind != ValID::t_GlobalID && Fn.Kind != ValID::t_GlobalName)
@@ -3960,7 +3978,7 @@ bool LLParser::parseGlobalValue(Type *Ty, Constant *&C) {
   C = nullptr;
   ValID ID;
   Value *V = nullptr;
-  bool Parsed = parseValID(ID) ||
+  bool Parsed = parseValID(ID, /*PFS=*/nullptr, Ty) ||
                 convertValIDToValue(Ty, ID, V, nullptr, /*IsCall=*/false);
   if (V && !(C = dyn_cast<Constant>(V)))
     return error(ID.Loc, "global values must be constants");
@@ -5679,7 +5697,9 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
     return false;
   case ValID::t_Constant:
     if (ID.ConstantVal->getType() != Ty)
-      return error(ID.Loc, "constant expression type mismatch");
+      return error(ID.Loc, "constant expression type mismatch: got type '" +
+                               getTypeString(ID.ConstantVal->getType()) +
+                               "' but expected '" + getTypeString(Ty) + "'");
     V = ID.ConstantVal;
     return false;
   case ValID::t_ConstantStruct:
@@ -5739,7 +5759,7 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) {
 bool LLParser::parseValue(Type *Ty, Value *&V, PerFunctionState *PFS) {
   V = nullptr;
   ValID ID;
-  return parseValID(ID, PFS) ||
+  return parseValID(ID, PFS, Ty) ||
          convertValIDToValue(Ty, ID, V, PFS, /*IsCall=*/false);
 }
 
@@ -6033,7 +6053,12 @@ bool LLParser::PerFunctionState::resolveForwardRefBlockAddresses() {
     if (!BB)
       return P.error(BBID.Loc, "referenced value is not a basic block");
 
-    GV->replaceAllUsesWith(BlockAddress::get(&F, BB));
+    Value *ResolvedVal = BlockAddress::get(&F, BB);
+    ResolvedVal = P.checkValidVariableType(BBID.Loc, BBID.StrVal, GV->getType(),
+                                           ResolvedVal, false);
+    if (!ResolvedVal)
+      return true;
+    GV->replaceAllUsesWith(ResolvedVal);
     GV->eraseFromParent();
   }
 
@@ -6568,7 +6593,7 @@ bool LLParser::parseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
   if (parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
       parseOptionalProgramAddrSpace(InvokeAddrSpace) ||
       parseType(RetType, RetTypeLoc, true /*void allowed*/) ||
-      parseValID(CalleeID) || parseParameterList(ArgList, PFS) ||
+      parseValID(CalleeID, &PFS) || parseParameterList(ArgList, PFS) ||
       parseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
                                  NoBuiltinLoc) ||
       parseOptionalOperandBundles(BundleList, PFS) ||
@@ -6876,7 +6901,7 @@ bool LLParser::parseCallBr(Instruction *&Inst, PerFunctionState &PFS) {
   BasicBlock *DefaultDest;
   if (parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
       parseType(RetType, RetTypeLoc, true /*void allowed*/) ||
-      parseValID(CalleeID) || parseParameterList(ArgList, PFS) ||
+      parseValID(CalleeID, &PFS) || parseParameterList(ArgList, PFS) ||
       parseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
                                  NoBuiltinLoc) ||
       parseOptionalOperandBundles(BundleList, PFS) ||
@@ -7303,7 +7328,7 @@ bool LLParser::parseCall(Instruction *&Inst, PerFunctionState &PFS,
   if (parseOptionalCallingConv(CC) || parseOptionalReturnAttrs(RetAttrs) ||
       parseOptionalProgramAddrSpace(CallAddrSpace) ||
       parseType(RetType, RetTypeLoc, true /*void allowed*/) ||
-      parseValID(CalleeID) ||
+      parseValID(CalleeID, &PFS) ||
       parseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail,
                          PFS.getFunction().isVarArg()) ||
       parseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, BuiltinLoc) ||
@@ -7979,9 +8004,9 @@ bool LLParser::parseUseListOrderBB() {
 
   ValID Fn, Label;
   SmallVector<unsigned, 16> Indexes;
-  if (parseValID(Fn) ||
+  if (parseValID(Fn, /*PFS=*/nullptr) ||
       parseToken(lltok::comma, "expected comma in uselistorder_bb directive") ||
-      parseValID(Label) ||
+      parseValID(Label, /*PFS=*/nullptr) ||
       parseToken(lltok::comma, "expected comma in uselistorder_bb directive") ||
       parseUseListOrderIndexes(Indexes))
     return true;

diff  --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 6dcf8b5b6a67d..bc197b98b327b 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -1829,8 +1829,8 @@ BlockAddress *BlockAddress::get(Function *F, BasicBlock *BB) {
 }
 
 BlockAddress::BlockAddress(Function *F, BasicBlock *BB)
-: Constant(Type::getInt8PtrTy(F->getContext()), Value::BlockAddressVal,
-           &Op<0>(), 2) {
+    : Constant(Type::getInt8PtrTy(F->getContext(), F->getAddressSpace()),
+               Value::BlockAddressVal, &Op<0>(), 2) {
   setOperand(0, F);
   setOperand(1, BB);
   BB->AdjustBlockAddressRefCount(1);

diff  --git a/llvm/test/Bitcode/blockaddress-addrspace.ll b/llvm/test/Bitcode/blockaddress-addrspace.ll
new file mode 100644
index 0000000000000..4d7a474bca3fa
--- /dev/null
+++ b/llvm/test/Bitcode/blockaddress-addrspace.ll
@@ -0,0 +1,286 @@
+; RUN: rm -rf %t && split-file %s %t
+; RUN: llvm-as %t/global-use-good.ll -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/global-use-bad.ll -o /dev/null 2>&1 | FileCheck %t/global-use-bad.ll
+; RUN: llvm-as %t/global-fwddecl-good.ll -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/global-fwddecl-bad.ll -o /dev/null 2>&1 | FileCheck %t/global-fwddecl-bad.ll
+; RUN: llvm-as %t/return-fwddecl-good.ll  -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/return-fwddecl-bad.ll -o /dev/null 2>&1 | FileCheck %t/return-fwddecl-bad.ll
+; RUN: llvm-as %t/return-self-good.ll  -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/return-self-bad.ll -o /dev/null 2>&1 | FileCheck %t/return-self-bad.ll
+; RUN: not llvm-as %t/return-self-bad-2.ll -o /dev/null 2>&1 | FileCheck %t/return-self-bad-2.ll
+; RUN: not llvm-as %t/return-unknown-fn-bad.ll -o /dev/null 2>&1 | FileCheck %t/return-unknown-fn-bad.ll
+; RUN: llvm-as %t/call-fwddecl-good.ll  -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/call-fwddecl-bad.ll -o /dev/null 2>&1 | FileCheck %t/call-fwddecl-bad.ll
+; RUN: llvm-as %t/phi-good.ll  -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/phi-bad.ll -o /dev/null 2>&1 | FileCheck %t/phi-bad.ll
+; RUN: llvm-as %t/fwddecl-phi-good.ll  -o - | llvm-dis -o /dev/null
+; RUN: not llvm-as %t/fwddecl-phi-bad.ll -o /dev/null 2>&1 | FileCheck %t/fwddecl-phi-bad.ll
+; RUN: not llvm-as %t/bad-type-not-ptr.ll -o /dev/null 2>&1 | FileCheck %t/bad-type-not-ptr.ll
+; RUN: not llvm-as %t/bad-type-not-i8-ptr.ll -o /dev/null 2>&1 | FileCheck %t/bad-type-not-i8-ptr.ll
+
+
+;--- global-use-good.ll
+target datalayout = "P2"
+define void @fn_in_prog_as_implicit() {
+  unreachable
+bb:
+  ret void
+}
+define void @fn_in_prog_as_explicit() addrspace(2) {
+  unreachable
+bb:
+  ret void
+}
+define void @fn_in_other_as() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+ at global1 = constant i8 addrspace(2)* blockaddress(@fn_in_prog_as_implicit, %bb)
+ at global2 = constant i8 addrspace(2)* blockaddress(@fn_in_prog_as_explicit, %bb)
+ at global3 = constant i8 addrspace(1)* blockaddress(@fn_in_other_as, %bb)
+
+;--- global-use-bad.ll
+define void @fn() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+ at global1 = constant i8 addrspace(2)* blockaddress(@fn, %bb)
+; CHECK: [[#@LINE-1]]:38: error: constant expression type mismatch: got type 'i8 addrspace(1)*' but expected 'i8 addrspace(2)*'
+
+; Check that a global blockaddress of a forward-declared function
+; uses the type of the global variable address space for the forward declaration
+;--- global-fwddecl-good.ll
+ at global = constant i8 addrspace(2)* blockaddress(@fwddecl_in_prog_as, %bb)
+define void @fwddecl_in_prog_as() addrspace(2) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- global-fwddecl-bad.ll
+; This forward declaration does not match the actual function type so we should get an error:
+ at global = constant i8 addrspace(2)* blockaddress(@fwddecl_in_unexpected_as, %bb)
+; CHECK: [[#@LINE-1]]:77: error: 'bb' defined with type 'i8 addrspace(1)*' but expected 'i8 addrspace(2)*'
+define void @fwddecl_in_unexpected_as() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+
+
+; When returning blockaddresses of forward-declared functions we
+; can also use the type of the variable.
+;--- return-fwddecl-good.ll
+define i8 addrspace(2)* @take_as2() {
+  ret i8 addrspace(2)* blockaddress(@fwddecl_as2, %bb)
+}
+define i8 addrspace(1)* @take_as1() {
+  ret i8 addrspace(1)* blockaddress(@fwddecl_as1, %bb)
+}
+define void @fwddecl_as1() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+define void @fwddecl_as2() addrspace(2) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- return-fwddecl-bad.ll
+define i8 addrspace(2)* @take_bad() {
+  ret i8 addrspace(2)* blockaddress(@fwddecl_as1, %bb)
+  ; CHECK: [[#@LINE-1]]:51: error: 'bb' defined with type 'i8 addrspace(1)*' but expected 'i8 addrspace(2)*'
+}
+define void @fwddecl_as1() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- return-self-good.ll
+target datalayout = "P2"
+define i8 addrspace(0)* @take_self_as0() addrspace(0) {
+L1:
+  br label %L2
+L2:
+  ret i8 addrspace(0)* blockaddress(@take_self_as0, %L3)
+L3:
+  unreachable
+}
+define i8 addrspace(2)* @take_self_prog_as() {
+L1:
+  br label %L2
+L2:
+  ret i8 addrspace(2)* blockaddress(@take_self_prog_as, %L3)
+L3:
+  unreachable
+}
+define i8 addrspace(1)* @take_self_as1() addrspace(1) {
+L1:
+  br label %L2
+L2:
+  ret i8 addrspace(1)* blockaddress(@take_self_as1, %L3)
+L3:
+  unreachable
+}
+define i8 addrspace(2)* @take_self_as2() addrspace(2) {
+L1:
+  br label %L2
+L2:
+  ret i8 addrspace(2)* blockaddress(@take_self_as2, %L3)
+L3:
+  unreachable
+}
+
+;--- return-self-bad.ll
+target datalayout = "P2"
+define i8 addrspace(2)* @take_self_bad() addrspace(1) {
+L1:
+  br label %L2
+L2:
+  ret i8 addrspace(2)* blockaddress(@take_self_bad, %L3)
+  ; CHECK: [[#@LINE-1]]:24: error: constant expression type mismatch: got type 'i8 addrspace(1)*' but expected 'i8 addrspace(2)*'
+L3:
+  unreachable
+}
+;--- return-self-bad-2.ll
+target datalayout = "P2"
+define i8* @take_self_bad_prog_as() {
+L1:
+  br label %L2
+L2:
+  ret i8* blockaddress(@take_self_bad_prog_as, %L3)
+  ; CHECK: [[#@LINE-1]]:11: error: constant expression type mismatch: got type 'i8 addrspace(2)*' but expected 'i8*'
+L3:
+  unreachable
+}
+
+;--- return-unknown-fn-bad.ll
+target datalayout = "P2"
+define i8 addrspace(1)* @return_unknown_fn() addrspace(1) {
+  ret i8 addrspace(1)* blockaddress(@undefined, %bb)
+  ; CHECK: [[#@LINE-1]]:37: error: expected function name in blockaddress
+}
+
+
+;--- call-fwddecl-good.ll
+target datalayout = "P2"
+define void @call_from_fn_in_as2() addrspace(2) {
+  call addrspace(2) void bitcast (i8 addrspace(2)* blockaddress(@fwddecl_as2, %bb) to void () addrspace(2)*)()
+  ret void
+}
+define void @call_from_fn_in_as1() addrspace(1) {
+  call addrspace(1) void bitcast (i8 addrspace(1)* blockaddress(@fwddecl_as1, %bb) to void () addrspace(1)*)()
+  ret void
+}
+define void @fwddecl_as2() addrspace(2) {
+  unreachable
+bb:
+  ret void
+}
+define void @fwddecl_as1() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- call-fwddecl-bad.ll
+target datalayout = "P2"
+define void @call_from_fn_in_as2_explicit() addrspace(2) {
+  call addrspace(2) void bitcast (i8 addrspace(2)* blockaddress(@fwddecl_as1, %bb) to void () addrspace(2)*)()
+  ; CHECK: [[#@LINE-1]]:79: error: 'bb' defined with type 'i8 addrspace(1)*' but expected 'i8 addrspace(2)*'
+  ret void
+}
+define void @fwddecl_as1() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- phi-good.ll
+target datalayout = "P2"
+define i8 addrspace(1)* @f1() addrspace(1) {
+L1:
+  br label %L3
+L2:
+  br label %L3
+L3:
+  %p = phi i8 addrspace(1)* [ blockaddress(@f1, %L4), %L2 ], [ null, %L1 ]
+  ret i8 addrspace(1)* %p
+L4:
+  unreachable
+}
+define i8 addrspace(2)* @f2() {
+L1:
+  br label %L3
+L2:
+  br label %L3
+L3:
+  %p = phi i8 addrspace(2)* [ blockaddress(@f2, %L4), %L2 ], [ null, %L1 ]
+  ret i8 addrspace(2)* %p
+L4:
+  unreachable
+}
+
+;--- phi-bad.ll
+target datalayout = "P2"
+define i8* @f() {
+L1:
+  br label %L3
+L2:
+  br label %L3
+L3:
+  %p = phi i8* [ blockaddress(@f, %L4), %L2 ], [ null, %L1 ]
+  ; CHECK: [[#@LINE-1]]:18: error: constant expression type mismatch: got type 'i8 addrspace(2)*' but expected 'i8*'
+  ret i8* %p
+}
+
+; A blockaddress function forward-declaration used in a phi node should
+; create the forward declaration in the same address space as the current function
+;--- fwddecl-phi-good.ll
+define i8 addrspace(1)* @f() addrspace(1) {
+L1:
+  br label %L3
+L2:
+  br label %L3
+L3:
+  %p = phi i8 addrspace(1)* [ blockaddress(@fwddecl_as1, %bb), %L2 ], [ null, %L1 ]
+  ret i8 addrspace(1)* %p
+L4:
+  unreachable
+}
+define void @fwddecl_as1() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- fwddecl-phi-bad.ll
+define i8 addrspace(2)* @f() addrspace(2) {
+L1:
+  br label %L3
+L2:
+  br label %L3
+L3:
+  %p = phi i8 addrspace(2)* [ blockaddress(@fwddecl_as1, %bb), %L2 ], [ null, %L1 ]
+  ; CHECK: [[#@LINE-1]]:58: error: 'bb' defined with type 'i8 addrspace(1)*' but expected 'i8 addrspace(2)*'
+  ret i8 addrspace(2)* %p
+L4:
+  unreachable
+}
+define void @fwddecl_as1() addrspace(1) {
+  unreachable
+bb:
+  ret void
+}
+
+;--- bad-type-not-ptr.ll
+ at global = constant i8 blockaddress(@unknown_fn, %bb)
+; CHECK: [[#@LINE-1]]:23: error: type of blockaddress must be a pointer and not 'i8'
+;--- bad-type-not-i8-ptr.ll
+ at global = constant i32* blockaddress(@unknown_fn, %bb)
+; CHECK: [[#@LINE-1]]:25: error: constant expression type mismatch: got type 'i8*' but expected 'i32*'

diff  --git a/llvm/test/CodeGen/AVR/block-address-is-in-progmem-space.ll b/llvm/test/CodeGen/AVR/block-address-is-in-progmem-space.ll
new file mode 100644
index 0000000000000..8e6e3a7106283
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/block-address-is-in-progmem-space.ll
@@ -0,0 +1,51 @@
+; RUN: llc -mcpu=atmega328 < %s -march=avr | FileCheck %s
+
+; This test verifies that the pointer to a basic block
+; should always be a pointer in address space 1.
+;
+; If this were not the case, then programs targeting
+; AVR that attempted to read their own machine code
+; via a pointer to a label would actually read from RAM
+; using a pointer relative to the the start of program flash.
+;
+; This would cause a load of uninitialized memory, not even
+; touching the program's machine code as otherwise desired.
+
+target datalayout = "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"
+
+; CHECK-LABEL: load_with_no_forward_reference
+define i8 @load_with_no_forward_reference(i8 %a, i8 %b) {
+second:
+  ; CHECK:      ldi r30, .Ltmp0+2
+  ; CHECK-NEXT: ldi r31, .Ltmp0+4
+  ; CHECK: lpm r24, Z
+  %bar = load i8, i8 addrspace(1)* blockaddress(@function_with_no_forward_reference, %second)
+  ret i8 %bar
+}
+
+; CHECK-LABEL: load_from_local_label
+define i8 @load_from_local_label(i8 %a, i8 %b) {
+entry:
+  %result1 = add i8 %a, %b
+
+  br label %second
+
+; CHECK-LABEL: .Ltmp1:
+second:
+  ; CHECK:      ldi r30, .Ltmp1+2
+  ; CHECK-NEXT: ldi r31, .Ltmp1+4
+  ; CHECK-NEXT: lpm r24, Z
+  %result2 = load i8, i8 addrspace(1)* blockaddress(@load_from_local_label, %second)
+  ret i8 %result2
+}
+
+; A function with no forward reference, right at the end
+; of the file.
+define i8 @function_with_no_forward_reference(i8 %a, i8 %b) {
+entry:
+  %result = add i8 %a, %b
+  br label %second
+second:
+  ret i8 0
+}
+

diff  --git a/llvm/test/CodeGen/AVR/brind.ll b/llvm/test/CodeGen/AVR/brind.ll
index 4eea966062db7..b66319c872fe5 100644
--- a/llvm/test/CodeGen/AVR/brind.ll
+++ b/llvm/test/CodeGen/AVR/brind.ll
@@ -1,15 +1,15 @@
 ; RUN: llc -mattr=sram,eijmpcall < %s -march=avr -verify-machineinstrs | FileCheck %s
 
- at brind.k = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@brind, %return), i8* blockaddress(@brind, %b)], align 1
+ at brind.k = private unnamed_addr constant [2 x i8 addrspace(1)*] [i8 addrspace(1)* blockaddress(@brind, %return), i8 addrspace(1)* blockaddress(@brind, %b)], align 1
 
 define i8 @brind(i8 %p) {
 ; CHECK-LABEL: brind:
 ; CHECK: ijmp
 entry:
   %idxprom = sext i8 %p to i16
-  %arrayidx = getelementptr inbounds [2 x i8*], [2 x i8*]* @brind.k, i16 0, i16 %idxprom
-  %s = load i8*, i8** %arrayidx
-  indirectbr i8* %s, [label %return, label %b]
+  %arrayidx = getelementptr inbounds [2 x i8 addrspace(1)*], [2 x i8 addrspace(1)*]* @brind.k, i16 0, i16 %idxprom
+  %s = load i8 addrspace(1)*, i8 addrspace(1)** %arrayidx
+  indirectbr i8 addrspace(1)* %s, [label %return, label %b]
 b:
   br label %return
 return:


        


More information about the llvm-commits mailing list