diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -3737,7 +3737,16 @@ ``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 program +memory address space specified in the data layout. For targets that place +code and data in the same address space (Von-Neumann architectures) a block +address will have the same address space as data pointers, usually +``addrspace(0)``. Block addresses on targets that have different data and +code address spaces (Harvard architectures) will always be in the program +memory address space specified in the target's data layout. + 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/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3387,9 +3387,13 @@ std::map())) .first->second.insert(std::make_pair(std::move(Label), nullptr)) .first->second; - if (!FwdRef) + if (!FwdRef) { FwdRef = new GlobalVariable(*M, Type::getInt8Ty(Context), false, - GlobalValue::InternalLinkage, nullptr, ""); + GlobalValue::InternalLinkage, nullptr, "", + nullptr, GlobalValue::NotThreadLocal, + M->getDataLayout().getProgramAddressSpace()); + } + ID.ConstantVal = FwdRef; ID.Kind = ValID::t_Constant; return false; diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -1702,8 +1702,8 @@ } 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/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 --- /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 --- 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 -@brind.k = private unnamed_addr constant [2 x i8*] [i8* blockaddress(@brind, %return), i8* blockaddress(@brind, %b)], align 1 +@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: