Index: llvm/include/llvm/Transforms/Scalar/RThreadAccess.h =================================================================== --- /dev/null +++ llvm/include/llvm/Transforms/Scalar/RThreadAccess.h @@ -0,0 +1,54 @@ +//===- RThreadAccess.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// \file +// This file provides the interface for RThreadAccess pass. +// To pointer operands of load and store instructions RThreadAccess adds Thread +// Pointer Register (rthread), specified by the option -rthread-register as a +// base to pointers of addrspace specified by the option -rthread-addrspace. +// +// For example, the following load and store: +// +// %v1 = load volatile i64, ptr addrspace(256) +// inttoptr (i64 816 to ptr addrspace(256)), align 8 +// store volatile i64 164, ptr addrspace(255) +// inttoptr(i64 416 to ptr addrspace(256)), align 8 +// +// are converted to the following (where -rthread-register=r15 +// -rthread-addrspace=256): +// +// %tls1 = call i64 @llvm.read_register.i64(metadata !{!"r15"}) +// %ptri1 = add i64 %tls1, 816 +// %tls1.field = inttoptr i64 %ptri1 to ptr +// %v1 = load volatile i64, ptr %tls1.field, align 8 +// +// %tls2 = call i64 @llvm.read_register.i64(metadata !{!"r15"}) +// %ptri2 = add i64 %tls2, 416 +// %tls2.field = inttoptr i64 %ptri2 to ptr +// store volatile i64 164, ptr %tls2.field, align 8 +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/PassManager.h" +#include "llvm/Support/CommandLine.h" + +extern llvm::cl::opt ReservedThreadPointerRegister; + +namespace llvm { + +class FunctionPass; + +FunctionPass *createRThreadAccessPass(); + +class RThreadAccess : public PassInfoMixin { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + bool runImpl(Function &F); +}; + +} // end namespace llvm Index: llvm/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/lib/Passes/PassBuilder.cpp +++ llvm/lib/Passes/PassBuilder.cpp @@ -206,6 +206,7 @@ #include "llvm/Transforms/Scalar/NewGVN.h" #include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h" #include "llvm/Transforms/Scalar/PlaceSafepoints.h" +#include "llvm/Transforms/Scalar/RThreadAccess.h" #include "llvm/Transforms/Scalar/Reassociate.h" #include "llvm/Transforms/Scalar/Reg2Mem.h" #include "llvm/Transforms/Scalar/RewriteStatepointsForGC.h" Index: llvm/lib/Passes/PassRegistry.def =================================================================== --- llvm/lib/Passes/PassRegistry.def +++ llvm/lib/Passes/PassRegistry.def @@ -383,6 +383,7 @@ FUNCTION_PASS("reassociate", ReassociatePass()) FUNCTION_PASS("redundant-dbg-inst-elim", RedundantDbgInstEliminationPass()) FUNCTION_PASS("reg2mem", RegToMemPass()) +FUNCTION_PASS("rthread-access", RThreadAccess()) FUNCTION_PASS("scalarize-masked-mem-intrin", ScalarizeMaskedMemIntrinPass()) FUNCTION_PASS("scalarizer", ScalarizerPass()) FUNCTION_PASS("separate-const-offset-from-gep", SeparateConstOffsetFromGEPPass()) Index: llvm/lib/Target/AArch64/AArch64Subtarget.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -25,6 +25,7 @@ #include "llvm/CodeGen/MachineScheduler.h" #include "llvm/IR/GlobalValue.h" #include "llvm/TargetParser/AArch64TargetParser.h" +#include "llvm/Transforms/Scalar/RThreadAccess.h" using namespace llvm; @@ -285,6 +286,9 @@ } } +#define GET_REGISTER_MATCHER +#include "AArch64GenAsmMatcher.inc" + AArch64Subtarget::AArch64Subtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS, const TargetMachine &TM, bool LittleEndian, @@ -304,6 +308,12 @@ if (AArch64::isX18ReservedByDefault(TT)) ReserveXRegister.set(18); + if (!ReservedThreadPointerRegister.empty()) // if defined. + if (auto Reg = MatchRegisterName(ReservedThreadPointerRegister.c_str())) { + unsigned DwarfRegNum = getRegisterInfo()->getDwarfRegNum(Reg, false); + ReserveXRegister.set(DwarfRegNum); + } + CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering())); InlineAsmLoweringInfo.reset(new InlineAsmLowering(getTargetLowering())); Legalizer.reset(new AArch64LegalizerInfo(*this)); Index: llvm/lib/Target/AArch64/AArch64TargetMachine.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -49,6 +49,7 @@ #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/CFGuard.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/RThreadAccess.h" #include #include #include @@ -644,6 +645,9 @@ MergeExternalByDefault)); } + if (!ReservedThreadPointerRegister.empty()) // if defined. + addPass(createRThreadAccessPass()); + return false; } Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -29501,6 +29501,9 @@ return FrameAddr; } +#define GET_REGISTER_MATCHER +#include "X86GenAsmMatcher.inc" + // FIXME? Maybe this could be a TableGen attribute on some registers and // this table could be generated automatically from RegInfo. Register X86TargetLowering::getRegisterByName(const char* RegName, LLT VT, @@ -29514,6 +29517,11 @@ .Case("rbp", X86::RBP) .Default(0); + // TODO: Intention of getRegisterByName() is to return only non-allocatable + // regs. See LLVM Lang Ref about @lvm.read.register(). + if (!Reg) + Reg = MatchRegisterName(RegName); + if (Reg == X86::EBP || Reg == X86::RBP) { if (!TFI.hasFP(MF)) report_fatal_error("register " + StringRef(RegName) + Index: llvm/lib/Target/X86/X86RegisterInfo.cpp =================================================================== --- llvm/lib/Target/X86/X86RegisterInfo.cpp +++ llvm/lib/Target/X86/X86RegisterInfo.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/Scalar/RThreadAccess.h" using namespace llvm; @@ -524,6 +525,9 @@ return CSR_64_TLS_Darwin_RegMask; } +#define GET_REGISTER_MATCHER +#include "X86GenAsmMatcher.inc" + BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const { BitVector Reserved(getNumRegs()); const X86FrameLowering *TFI = getFrameLowering(MF); @@ -554,6 +558,13 @@ Reserved.set(SubReg); } + // Set rthread as reserved. + if (!ReservedThreadPointerRegister.empty()) { + auto Reg = MatchRegisterName(ReservedThreadPointerRegister.c_str()); + for (const MCPhysReg &SubReg : subregs_inclusive(Reg)) + Reserved.set(SubReg); + } + // Set the base-pointer register and its aliases as reserved if needed. if (hasBasePointer(MF)) { CallingConv::ID CC = MF.getFunction().getCallingConv(); Index: llvm/lib/Target/X86/X86TargetMachine.cpp =================================================================== --- llvm/lib/Target/X86/X86TargetMachine.cpp +++ llvm/lib/Target/X86/X86TargetMachine.cpp @@ -50,6 +50,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/CFGuard.h" +#include "llvm/Transforms/Scalar/RThreadAccess.h" #include #include #include @@ -512,6 +513,9 @@ } bool X86PassConfig::addPreISel() { + if (!ReservedThreadPointerRegister.empty()) // if defined. + addPass(createRThreadAccessPass()); + // Only add this pass for 32-bit x86 Windows. const Triple &TT = TM->getTargetTriple(); if (TT.isOSWindows() && TT.getArch() == Triple::x86) Index: llvm/lib/Transforms/Scalar/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Scalar/CMakeLists.txt +++ llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -63,6 +63,7 @@ Reassociate.cpp Reg2Mem.cpp RewriteStatepointsForGC.cpp + RThreadAccess.cpp SCCP.cpp SROA.cpp Scalar.cpp Index: llvm/lib/Transforms/Scalar/RThreadAccess.cpp =================================================================== --- /dev/null +++ llvm/lib/Transforms/Scalar/RThreadAccess.cpp @@ -0,0 +1,193 @@ +//===- RThreadAccess.cpp - rthread-access pass ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/RThreadAccess.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/PassRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "rthread-access" + +llvm::cl::opt ReservedThreadPointerRegister( + "rthread-register", cl::ZeroOrMore, cl::Hidden, + cl::desc("Register that must be hidden from register allocator and is " + "preserved across function calls. This register is used as base " + "pointer for addrspace(-rthread-addrspace).")); + +llvm::cl::opt + ThreadPointerAddrspace("rthread-addrspace", cl::init(256), cl::ZeroOrMore, + cl::Hidden, + cl::desc("Addrspace denoting rthread access.")); + +PreservedAnalyses RThreadAccess::run(Function &F, FunctionAnalysisManager &AM) { + bool MadeChange = runImpl(F); + if (!MadeChange) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} + +#ifndef NDEBUG +// Check that constant expression do not cast from +// addrspace(ThreadPointerAddrspace). +// Returns error message, null for successful verification. +static const char *verificationErrorMsg(const ConstantExpr &CE) { + if (CE.getOpcode() == Instruction::AddrSpaceCast) { + if (CE.getOperand(0)->getType()->getPointerAddressSpace() == + ThreadPointerAddrspace && + CE.getType()->getPointerAddressSpace() != ThreadPointerAddrspace) + return "Prohibited AddrSpaceCast from ThreadPointerAddrspace"; + } else if (CE.getOpcode() == Instruction::PtrToInt) { + if (CE.getOperand(0)->getType()->getPointerAddressSpace() == + ThreadPointerAddrspace) + return "Prohibited PtrToInt from ThreadPointerAddrspace"; + } + + for (Value *Op : CE.operands()) + if (auto *OpCE = dyn_cast(Op)) + if (auto *Error = verificationErrorMsg(*OpCE)) + return Error; + + return nullptr; // No error. +} + +// Check that instruction do not cast from addrspace(ThreadPointerAddrspace). +// Returns error message, null for successful verification. +static const char *verificationErrorMsg(const Instruction &I) { + if (auto *ASCI = dyn_cast(&I)) { + if (ASCI->getSrcAddressSpace() == ThreadPointerAddrspace && + ASCI->getDestAddressSpace() != ThreadPointerAddrspace) + return "Prohibited AddrSpaceCast from ThreadPointerAddrspace"; + } else if (auto *PTI = dyn_cast(&I)) { + if (PTI->getPointerAddressSpace() == ThreadPointerAddrspace) + return "Prohibited PtrToInt from ThreadPointerAddrspace"; + } + + for (Value *Op : I.operands()) + if (auto *CE = dyn_cast(Op)) + if (auto *Error = verificationErrorMsg(*CE)) + return Error; + + return nullptr; // No error. +} +#endif // NDEBUG + +// One instance of RThreadAccessBuilder is lazily created if at least one +// modification is needed in the passed function. This one instance is used +// for all modifications. +class RThreadAccessBuilder { + Module *M; + LLVMContext *C; + Type *IntptrTy; + MDNode *RegName; + Function *ReadRegister; + SmallVector RThreadArgs; + +public: + RThreadAccessBuilder(Function &F) + : M(F.getParent()), C(&M->getContext()), + IntptrTy(M->getDataLayout().getIntPtrType(*C, ThreadPointerAddrspace)), + RegName(MDNode::get( + *C, {MDString::get(*C, ReservedThreadPointerRegister)})), + ReadRegister( + Intrinsic::getDeclaration(M, Intrinsic::read_register, IntptrTy)), + RThreadArgs({MetadataAsValue::get(*C, RegName)}) {} + + Value *build(Instruction &I, Value *Ptr) { + IRBuilder<> IRB(&I); + Value *RThread = IRB.CreateCall(ReadRegister, RThreadArgs, "tls"); + Value *Offset = IRB.CreatePtrToInt(Ptr, IntptrTy, "offset"); + Value *PtrI = IRB.CreateAdd(RThread, Offset, "ptri"); // TODO: nsw nuw? + Value *Rebased = + IRB.CreateIntToPtr(PtrI, + PointerType::getWithSamePointeeType( + cast(Ptr->getType()), 0), + "tls.field"); + return Rebased; + } +}; + +bool RThreadAccess::runImpl(Function &F) { + if (ReservedThreadPointerRegister.empty()) // if undef. + return false; // Consider not adding this pass to the pipeline. + + std::optional Builder; // Lazily created. + + for (Instruction &I : instructions(F)) { + unsigned POI; + if (auto *LI = dyn_cast(&I)) { + POI = LI->getPointerOperandIndex(); + } else if (auto *SI = dyn_cast(&I)) { + POI = SI->getPointerOperandIndex(); + } else { +#ifndef NDEBUG + // TODO: Consider moving this check along with the verificationErrorMsg() + // methods under the EXPENSIVE_CHECKS macro once tested for a while. + if (auto *Error = verificationErrorMsg(I)) + llvm_unreachable(Error); +#endif + continue; + } + + Value *OP = I.getOperand(POI); + assert(OP->getType()->isPointerTy()); + if (OP->getType()->getPointerAddressSpace() != ThreadPointerAddrspace) + continue; + + if (!Builder) + Builder = RThreadAccessBuilder(F); + + auto *Rebased = Builder->build(I, OP); + LLVM_DEBUG(dbgs() << "RThreadAccess: replaced operand " << POI + << " in instruction " << I << "\n with " << *Rebased + << "\n";); + I.setOperand(POI, Rebased); + } + + return Builder.has_value(); +} + +namespace llvm { +void initializeRThreadAccessPassPass(PassRegistry &); +} + +class RThreadAccessPass : public FunctionPass { + RThreadAccess Pass; + +public: + static char ID; + + // Default constructor required for the INITIALIZE_PASS macro. + RThreadAccessPass() : FunctionPass(ID) { + initializeRThreadAccessPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + if (skipFunction(F)) + return false; + return Pass.runImpl(F); + } +}; + +char RThreadAccessPass::ID = 0; + +INITIALIZE_PASS(RThreadAccessPass, DEBUG_TYPE, "RThreadAccess", false, false) + +FunctionPass *llvm::createRThreadAccessPass() { + return new RThreadAccessPass(); +} Index: llvm/test/CodeGen/AArch64/rthread.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/rthread.ll @@ -0,0 +1,213 @@ +; RUN: opt -S -passes=rthread-access -rthread-register=x28 %s | FileCheck --check-prefixes=OPT %s +; RUN: llc --filetype=asm --march=aarch64 -rthread-register=x28 -o - %s | FileCheck --check-prefixes=ASM %s + +define i1 @types() { +; OPT-LABEL: @types( +; OPT-NEXT: [[TLS:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0:![0-9]+]]) +; OPT-NEXT: [[PTRI:%.*]] = add i64 [[TLS]], 816 +; OPT-NEXT: [[TLS_FIELD:%.*]] = inttoptr i64 [[PTRI]] to ptr +; OPT-NEXT: [[V1:%.*]] = load volatile i64, ptr [[TLS_FIELD]], align 8 +; OPT-NEXT: [[TLS1:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI2:%.*]] = add i64 [[TLS1]], 824 +; OPT-NEXT: [[TLS_FIELD3:%.*]] = inttoptr i64 [[PTRI2]] to ptr +; OPT-NEXT: [[V2:%.*]] = load volatile i32, ptr [[TLS_FIELD3]], align 8 +; OPT-NEXT: [[TLS4:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI5:%.*]] = add i64 [[TLS4]], 832 +; OPT-NEXT: [[TLS_FIELD6:%.*]] = inttoptr i64 [[PTRI5]] to ptr +; OPT-NEXT: [[V3:%.*]] = load volatile i16, ptr [[TLS_FIELD6]], align 8 +; OPT-NEXT: [[TLS7:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI8:%.*]] = add i64 [[TLS7]], 840 +; OPT-NEXT: [[TLS_FIELD9:%.*]] = inttoptr i64 [[PTRI8]] to ptr +; OPT-NEXT: [[V4:%.*]] = load volatile i8, ptr [[TLS_FIELD9]], align 8 +; OPT-NEXT: [[TLS10:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI11:%.*]] = add i64 [[TLS10]], 848 +; OPT-NEXT: [[TLS_FIELD12:%.*]] = inttoptr i64 [[PTRI11]] to ptr +; OPT-NEXT: [[V5:%.*]] = load volatile i1, ptr [[TLS_FIELD12]], align 8 +; OPT-NEXT: [[TLS13:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI14:%.*]] = add i64 [[TLS13]], 856 +; OPT-NEXT: [[TLS_FIELD15:%.*]] = inttoptr i64 [[PTRI14]] to ptr +; OPT-NEXT: [[V6:%.*]] = load volatile ptr, ptr [[TLS_FIELD15]], align 8 +; OPT-NEXT: [[TLS16:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI17:%.*]] = add i64 [[TLS16]], 864 +; OPT-NEXT: [[TLS_FIELD18:%.*]] = inttoptr i64 [[PTRI17]] to ptr +; OPT-NEXT: [[V7:%.*]] = load volatile ptr, ptr [[TLS_FIELD18]], align 8 +; OPT-NEXT: [[TLS19:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI20:%.*]] = add i64 [[TLS19]], 872 +; OPT-NEXT: [[TLS_FIELD21:%.*]] = inttoptr i64 [[PTRI20]] to ptr +; OPT-NEXT: [[V8:%.*]] = load volatile ptr, ptr [[TLS_FIELD21]], align 8 +; OPT-NEXT: [[TLS22:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI23:%.*]] = add i64 [[TLS22]], 416 +; OPT-NEXT: [[TLS_FIELD24:%.*]] = inttoptr i64 [[PTRI23]] to ptr +; OPT-NEXT: store volatile i64 164, ptr [[TLS_FIELD24]], align 8 +; OPT-NEXT: [[TLS25:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI26:%.*]] = add i64 [[TLS25]], 424 +; OPT-NEXT: [[TLS_FIELD27:%.*]] = inttoptr i64 [[PTRI26]] to ptr +; OPT-NEXT: store volatile i32 132, ptr [[TLS_FIELD27]], align 8 +; OPT-NEXT: [[TLS28:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI29:%.*]] = add i64 [[TLS28]], 432 +; OPT-NEXT: [[TLS_FIELD30:%.*]] = inttoptr i64 [[PTRI29]] to ptr +; OPT-NEXT: store volatile i16 116, ptr [[TLS_FIELD30]], align 8 +; OPT-NEXT: [[TLS31:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI32:%.*]] = add i64 [[TLS31]], 440 +; OPT-NEXT: [[TLS_FIELD33:%.*]] = inttoptr i64 [[PTRI32]] to ptr +; OPT-NEXT: store volatile i8 18, ptr [[TLS_FIELD33]], align 8 +; OPT-NEXT: [[TLS34:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI35:%.*]] = add i64 [[TLS34]], 448 +; OPT-NEXT: [[TLS_FIELD36:%.*]] = inttoptr i64 [[PTRI35]] to ptr +; OPT-NEXT: store volatile i1 true, ptr [[TLS_FIELD36]], align 8 +; OPT-NEXT: [[TLS37:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI38:%.*]] = add i64 [[TLS37]], 456 +; OPT-NEXT: [[TLS_FIELD39:%.*]] = inttoptr i64 [[PTRI38]] to ptr +; OPT-NEXT: store volatile ptr null, ptr [[TLS_FIELD39]], align 8 +; OPT-NEXT: [[TLS40:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI41:%.*]] = add i64 [[TLS40]], 464 +; OPT-NEXT: [[TLS_FIELD42:%.*]] = inttoptr i64 [[PTRI41]] to ptr +; OPT-NEXT: store volatile ptr null, ptr [[TLS_FIELD42]], align 8 +; OPT-NEXT: [[TLS43:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI44:%.*]] = add i64 [[TLS43]], 472 +; OPT-NEXT: [[TLS_FIELD45:%.*]] = inttoptr i64 [[PTRI44]] to ptr +; OPT-NEXT: store volatile ptr null, ptr [[TLS_FIELD45]], align 8 +; +; ASM-LABEL: types: +; ASM: ldr x{{[0-9]+}}, [x28, #816] +; ASM: ldr w{{[0-9]+}}, [x28, #824] +; ASM: ldrh w{{[0-9]+}}, [x28, #832] +; ASM: ldrb w{{[0-9]+}}, [x28, #840] +; ASM: ldrb w{{[0-9]+}}, [x28, #848] +; ASM: ldr x{{[0-9]+}}, [x28, #856] +; ASM: ldr x{{[0-9]+}}, [x28, #864] +; ASM: ldr x{{[0-9]+}}, [x28, #872] +; ASM: str x{{[0-9]+}}, [x28, #416] +; ASM: str w{{[0-9]+}}, [x28, #424] +; ASM: strh w{{[0-9]+}}, [x28, #432] +; ASM: strb w{{[0-9]+}}, [x28, #440] +; ASM: strb w{{[0-9]+}}, [x28, #448] +; ASM: str xzr, [x28, #456] +; ASM: str xzr, [x28, #464] +; ASM: str xzr, [x28, #472] + %v1 = load volatile i64, ptr addrspace(256) inttoptr (i64 816 to ptr addrspace(256)), align 8 + %v2 = load volatile i32, ptr addrspace(256) inttoptr (i64 824 to ptr addrspace(256)), align 8 + %v3 = load volatile i16, ptr addrspace(256) inttoptr (i64 832 to ptr addrspace(256)), align 8 + %v4 = load volatile i8, ptr addrspace(256) inttoptr (i64 840 to ptr addrspace(256)), align 8 + %v5 = load volatile i1, ptr addrspace(256) inttoptr (i64 848 to ptr addrspace(256)), align 8 + %v6 = load volatile ptr, ptr addrspace(256) inttoptr (i64 856 to ptr addrspace(256)), align 8 + %v7 = load volatile ptr, ptr addrspace(256) inttoptr (i64 864 to ptr addrspace(256)), align 8 + %v8 = load volatile ptr, ptr addrspace(256) inttoptr (i64 872 to ptr addrspace(256)), align 8 + + store volatile i64 164, ptr addrspace(256) inttoptr (i64 416 to ptr addrspace(256)), align 8 + store volatile i32 132, ptr addrspace(256) inttoptr (i64 424 to ptr addrspace(256)), align 8 + store volatile i16 116, ptr addrspace(256) inttoptr (i64 432 to ptr addrspace(256)), align 8 + store volatile i8 18, ptr addrspace(256) inttoptr (i64 440 to ptr addrspace(256)), align 8 + store volatile i1 1, ptr addrspace(256) inttoptr (i64 448 to ptr addrspace(256)), align 8 + store volatile ptr null, ptr addrspace(256) inttoptr (i64 456 to ptr addrspace(256)), align 8 + store volatile ptr null, ptr addrspace(256) inttoptr (i64 464 to ptr addrspace(256)), align 8 + store volatile ptr null, ptr addrspace(256) inttoptr (i64 472 to ptr addrspace(256)), align 8 + + ; just collect results + %x1 = icmp eq i64 %v1, 0 + %x2 = icmp eq i32 %v2, 0 + %x3 = icmp eq i16 %v3, 0 + %x4 = icmp eq i8 %v4, 0 + %x5 = icmp eq i1 %v5, 0 + %x6 = icmp eq ptr %v6, null + %x7 = icmp eq ptr %v7, null + %x8 = icmp eq ptr %v8, null + %y2 = and i1 %x1, %x2 + %y3 = and i1 %y2, %x3 + %y4 = and i1 %y3, %x4 + %y5 = and i1 %y4, %x5 + %y6 = and i1 %y5, %x6 + %y7 = and i1 %y6, %x7 + %y8 = and i1 %y7, %x8 + + ret i1 %y8 +} + +define i1 @index_limits() { +; OPT-LABEL: @index_limits( +; OPT-NEXT: [[TLS:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI:%.*]] = add i64 [[TLS]], -256 +; OPT-NEXT: [[TLS_FIELD:%.*]] = inttoptr i64 [[PTRI]] to ptr +; OPT-NEXT: [[V8A:%.*]] = load volatile i8, ptr [[TLS_FIELD]], align 8 +; OPT-NEXT: [[TLS1:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI2:%.*]] = add i64 [[TLS1]], 4095 +; OPT-NEXT: [[TLS_FIELD3:%.*]] = inttoptr i64 [[PTRI2]] to ptr +; OPT-NEXT: [[V8B:%.*]] = load volatile i8, ptr [[TLS_FIELD3]], align 8 +; OPT-NEXT: [[TLS4:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI5:%.*]] = add i64 [[TLS4]], -256 +; OPT-NEXT: [[TLS_FIELD6:%.*]] = inttoptr i64 [[PTRI5]] to ptr +; OPT-NEXT: [[V16A:%.*]] = load volatile i16, ptr [[TLS_FIELD6]], align 8 +; OPT-NEXT: [[TLS7:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI8:%.*]] = add i64 [[TLS7]], 8190 +; OPT-NEXT: [[TLS_FIELD9:%.*]] = inttoptr i64 [[PTRI8]] to ptr +; OPT-NEXT: [[V16B:%.*]] = load volatile i16, ptr [[TLS_FIELD9]], align 8 +; OPT-NEXT: [[TLS10:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI11:%.*]] = add i64 [[TLS10]], -256 +; OPT-NEXT: [[TLS_FIELD12:%.*]] = inttoptr i64 [[PTRI11]] to ptr +; OPT-NEXT: [[V32A:%.*]] = load volatile i32, ptr [[TLS_FIELD12]], align 8 +; OPT-NEXT: [[TLS13:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI14:%.*]] = add i64 [[TLS13]], 16380 +; OPT-NEXT: [[TLS_FIELD15:%.*]] = inttoptr i64 [[PTRI14]] to ptr +; OPT-NEXT: [[V32B:%.*]] = load volatile i32, ptr [[TLS_FIELD15]], align 8 +; OPT-NEXT: [[TLS16:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI17:%.*]] = add i64 [[TLS16]], -256 +; OPT-NEXT: [[TLS_FIELD18:%.*]] = inttoptr i64 [[PTRI17]] to ptr +; OPT-NEXT: [[V64A:%.*]] = load volatile i64, ptr [[TLS_FIELD18]], align 8 +; OPT-NEXT: [[TLS19:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI20:%.*]] = add i64 [[TLS19]], 32760 +; OPT-NEXT: [[TLS_FIELD21:%.*]] = inttoptr i64 [[PTRI20]] to ptr +; OPT-NEXT: [[V64B:%.*]] = load volatile i64, ptr [[TLS_FIELD21]], align 8 +; +; ASM-LABEL: index_limits: +; ASM: ldurb w{{[0-9]+}}, [x28, #-256] +; ASM: ldrb w{{[0-9]+}}, [x28, #4095] +; ASM: ldurh w{{[0-9]+}}, [x28, #-256] +; ASM: ldrh w{{[0-9]+}}, [x28, #8190] +; ASM: ldur w{{[0-9]+}}, [x28, #-256] +; ASM: ldr w{{[0-9]+}}, [x28, #16380] +; ASM: ldur x{{[0-9]+}}, [x28, #-256] +; ASM: ldr x{{[0-9]+}}, [x28, #32760] + %v8a = load volatile i8, ptr addrspace(256) inttoptr (i64 -256 to ptr addrspace(256)), align 8 + %v8b = load volatile i8, ptr addrspace(256) inttoptr (i64 4095 to ptr addrspace(256)), align 8 + %v16a = load volatile i16, ptr addrspace(256) inttoptr (i64 -256 to ptr addrspace(256)), align 8 + %v16b = load volatile i16, ptr addrspace(256) inttoptr (i64 8190 to ptr addrspace(256)), align 8 + %v32a = load volatile i32, ptr addrspace(256) inttoptr (i64 -256 to ptr addrspace(256)), align 8 + %v32b = load volatile i32, ptr addrspace(256) inttoptr (i64 16380 to ptr addrspace(256)), align 8 + %v64a = load volatile i64, ptr addrspace(256) inttoptr (i64 -256 to ptr addrspace(256)), align 8 + %v64b = load volatile i64, ptr addrspace(256) inttoptr (i64 32760 to ptr addrspace(256)), align 8 + + ; just collect results + %x8 = icmp eq i8 %v8a, %v8b + %x16 = icmp eq i16 %v16a, %v16b + %x32 = icmp eq i32 %v32a, %v32b + %x64 = icmp eq i64 %v64a, %v64b + %y1 = xor i1 %x8, %x16 + %y2 = xor i1 %x32, %x64 + %y3 = xor i1 %y1, %y2 + + ret i1 %y3 +} + +; addrspace(256) must not be cast to int but +; this case does not fail because LLVM parser translates it to "ret i64 816". +define i64 @cast-from-p256-to-i64() { +; OPT-LABEL: @cast-from-p256-to-i64 +; OPT-NEXT: ret i64 816 + ret i64 ptrtoint (ptr addrspace(256) inttoptr (i64 816 to ptr addrspace(256)) to i64) +} + +; No cast constraints for addrspace(257). +define void @cast-from-p257-to-i64() { +; OPT-LABEL: @cast-from-p257-to-i64 +; OPT-NEXT: ptrtoint + %v = ptrtoint ptr addrspace(257) null to i64 + ret void +} + +define void @cast-from-p257-to-p256() { +; OPT-LABEL: @cast-from-p257-to-p256 +; OPT-NEXT: addrspacecast + %v = addrspacecast ptr addrspace(257) null to ptr addrspace(256) + ret void +} + Index: llvm/test/CodeGen/X86/named-reg-alloc.ll =================================================================== --- llvm/test/CodeGen/X86/named-reg-alloc.ll +++ llvm/test/CodeGen/X86/named-reg-alloc.ll @@ -11,4 +11,4 @@ declare i32 @llvm.read_register.i32(metadata) nounwind -!0 = !{!"eax\00"} +!0 = !{!"InvalidRegister\00"} Index: llvm/test/CodeGen/X86/rthread.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/rthread.ll @@ -0,0 +1,203 @@ +; RUN: opt -S -passes=rthread-access -rthread-addrspace=255 -rthread-register=r15 %s | FileCheck --check-prefixes=OPT %s +; RUN: llc --filetype=asm --march=x86-64 -rthread-addrspace=255 -rthread-register=r15 -o - %s | FileCheck --check-prefixes=ASM %s + +define i1 @types() { +; OPT-LABEL: @types( +; OPT-NEXT: [[TLS:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0:![0-9]+]]) +; OPT-NEXT: [[PTRI:%.*]] = add i64 [[TLS]], 816 +; OPT-NEXT: [[TLS_FIELD:%.*]] = inttoptr i64 [[PTRI]] to ptr +; OPT-NEXT: [[V1:%.*]] = load volatile i64, ptr [[TLS_FIELD]], align 8 +; OPT-NEXT: [[TLS1:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI2:%.*]] = add i64 [[TLS1]], 824 +; OPT-NEXT: [[TLS_FIELD3:%.*]] = inttoptr i64 [[PTRI2]] to ptr +; OPT-NEXT: [[V2:%.*]] = load volatile i32, ptr [[TLS_FIELD3]], align 8 +; OPT-NEXT: [[TLS4:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI5:%.*]] = add i64 [[TLS4]], 832 +; OPT-NEXT: [[TLS_FIELD6:%.*]] = inttoptr i64 [[PTRI5]] to ptr +; OPT-NEXT: [[V3:%.*]] = load volatile i16, ptr [[TLS_FIELD6]], align 8 +; OPT-NEXT: [[TLS7:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI8:%.*]] = add i64 [[TLS7]], 840 +; OPT-NEXT: [[TLS_FIELD9:%.*]] = inttoptr i64 [[PTRI8]] to ptr +; OPT-NEXT: [[V4:%.*]] = load volatile i8, ptr [[TLS_FIELD9]], align 8 +; OPT-NEXT: [[TLS10:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI11:%.*]] = add i64 [[TLS10]], 848 +; OPT-NEXT: [[TLS_FIELD12:%.*]] = inttoptr i64 [[PTRI11]] to ptr +; OPT-NEXT: [[V5:%.*]] = load volatile i1, ptr [[TLS_FIELD12]], align 8 +; OPT-NEXT: [[TLS13:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI14:%.*]] = add i64 [[TLS13]], 856 +; OPT-NEXT: [[TLS_FIELD15:%.*]] = inttoptr i64 [[PTRI14]] to ptr +; OPT-NEXT: [[V6:%.*]] = load volatile ptr, ptr [[TLS_FIELD15]], align 8 +; OPT-NEXT: [[TLS16:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI17:%.*]] = add i64 [[TLS16]], 864 +; OPT-NEXT: [[TLS_FIELD18:%.*]] = inttoptr i64 [[PTRI17]] to ptr +; OPT-NEXT: [[V7:%.*]] = load volatile ptr, ptr [[TLS_FIELD18]], align 8 +; OPT-NEXT: [[TLS19:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI20:%.*]] = add i64 [[TLS19]], 872 +; OPT-NEXT: [[TLS_FIELD21:%.*]] = inttoptr i64 [[PTRI20]] to ptr +; OPT-NEXT: [[V8:%.*]] = load volatile ptr, ptr [[TLS_FIELD21]], align 8 +; OPT-NEXT: [[TLS22:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI23:%.*]] = add i64 [[TLS22]], 416 +; OPT-NEXT: [[TLS_FIELD24:%.*]] = inttoptr i64 [[PTRI23]] to ptr +; OPT-NEXT: store volatile i64 164, ptr [[TLS_FIELD24]], align 8 +; OPT-NEXT: [[TLS25:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI26:%.*]] = add i64 [[TLS25]], 424 +; OPT-NEXT: [[TLS_FIELD27:%.*]] = inttoptr i64 [[PTRI26]] to ptr +; OPT-NEXT: store volatile i32 132, ptr [[TLS_FIELD27]], align 8 +; OPT-NEXT: [[TLS28:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI29:%.*]] = add i64 [[TLS28]], 432 +; OPT-NEXT: [[TLS_FIELD30:%.*]] = inttoptr i64 [[PTRI29]] to ptr +; OPT-NEXT: store volatile i16 116, ptr [[TLS_FIELD30]], align 8 +; OPT-NEXT: [[TLS31:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI32:%.*]] = add i64 [[TLS31]], 440 +; OPT-NEXT: [[TLS_FIELD33:%.*]] = inttoptr i64 [[PTRI32]] to ptr +; OPT-NEXT: store volatile i8 18, ptr [[TLS_FIELD33]], align 8 +; OPT-NEXT: [[TLS34:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI35:%.*]] = add i64 [[TLS34]], 448 +; OPT-NEXT: [[TLS_FIELD36:%.*]] = inttoptr i64 [[PTRI35]] to ptr +; OPT-NEXT: store volatile i1 true, ptr [[TLS_FIELD36]], align 8 +; OPT-NEXT: [[TLS37:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI38:%.*]] = add i64 [[TLS37]], 456 +; OPT-NEXT: [[TLS_FIELD39:%.*]] = inttoptr i64 [[PTRI38]] to ptr +; OPT-NEXT: store volatile ptr null, ptr [[TLS_FIELD39]], align 8 +; OPT-NEXT: [[TLS40:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI41:%.*]] = add i64 [[TLS40]], 464 +; OPT-NEXT: [[TLS_FIELD42:%.*]] = inttoptr i64 [[PTRI41]] to ptr +; OPT-NEXT: store volatile ptr null, ptr [[TLS_FIELD42]], align 8 +; OPT-NEXT: [[TLS43:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI44:%.*]] = add i64 [[TLS43]], 472 +; OPT-NEXT: [[TLS_FIELD45:%.*]] = inttoptr i64 [[PTRI44]] to ptr +; OPT-NEXT: store volatile ptr null, ptr [[TLS_FIELD45]], align 8 +; +; ASM-LABEL: types: +; ASM: cmpq $0, 816(%r15) +; ASM: cmpl $0, 824(%r15) +; ASM: cmpw $0, 832(%r15) +; ASM: cmpb $0, 840(%r15) +; ASM: movzbl 848(%r15), +; ASM: cmpq $0, 856(%r15) +; ASM: cmpq $0, 864(%r15) +; ASM: cmpq $0, 872(%r15) +; ASM: movq $164, 416(%r15) +; ASM: movl $132, 424(%r15) +; ASM: movw $116, 432(%r15) +; ASM: movb $18, 440(%r15) +; ASM: movb $1, 448(%r15) +; ASM: movq $0, 456(%r15) +; ASM: movq $0, 464(%r15) +; ASM: movq $0, 472(%r15) + %v1 = load volatile i64, ptr addrspace(255) inttoptr (i64 816 to ptr addrspace(255)), align 8 + %v2 = load volatile i32, ptr addrspace(255) inttoptr (i64 824 to ptr addrspace(255)), align 8 + %v3 = load volatile i16, ptr addrspace(255) inttoptr (i64 832 to ptr addrspace(255)), align 8 + %v4 = load volatile i8 , ptr addrspace(255) inttoptr (i64 840 to ptr addrspace(255)), align 8 + %v5 = load volatile i1 , ptr addrspace(255) inttoptr (i64 848 to ptr addrspace(255)), align 8 + %v6 = load volatile ptr, ptr addrspace(255) inttoptr (i64 856 to ptr addrspace(255)), align 8 + %v7 = load volatile ptr , ptr addrspace(255) inttoptr (i64 864 to ptr addrspace(255)), align 8 + %v8 = load volatile ptr , ptr addrspace(255) inttoptr (i64 872 to ptr addrspace(255)), align 8 + + store volatile i64 164, ptr addrspace(255) inttoptr (i64 416 to ptr addrspace(255)), align 8 + store volatile i32 132, ptr addrspace(255) inttoptr (i64 424 to ptr addrspace(255)), align 8 + store volatile i16 116, ptr addrspace(255) inttoptr (i64 432 to ptr addrspace(255)), align 8 + store volatile i8 18, ptr addrspace(255) inttoptr (i64 440 to ptr addrspace(255)), align 8 + store volatile i1 1, ptr addrspace(255) inttoptr (i64 448 to ptr addrspace(255)), align 8 + store volatile ptr null, ptr addrspace(255) inttoptr (i64 456 to ptr addrspace(255)), align 8 + store volatile ptr null, ptr addrspace(255) inttoptr (i64 464 to ptr addrspace(255)), align 8 + store volatile ptr null, ptr addrspace(255) inttoptr (i64 472 to ptr addrspace(255)), align 8 + + ; just collect results + %x1 = icmp eq i64 %v1, 0 + %x2 = icmp eq i32 %v2, 0 + %x3 = icmp eq i16 %v3, 0 + %x4 = icmp eq i8 %v4, 0 + %x5 = icmp eq i1 %v5, 0 + %x6 = icmp eq ptr %v6, null + %x7 = icmp eq ptr %v7, null + %x8 = icmp eq ptr %v8, null + %y2 = and i1 %x1, %x2 + %y3 = and i1 %y2, %x3 + %y4 = and i1 %y3, %x4 + %y5 = and i1 %y4, %x5 + %y6 = and i1 %y5, %x6 + %y7 = and i1 %y6, %x7 + %y8 = and i1 %y7, %x8 + + ret i1 %y8 +} + +define i1 @index_limits() { +; OPT-LABEL: @index_limits( +; OPT-NEXT: [[TLS:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI:%.*]] = add i64 [[TLS]], -255 +; OPT-NEXT: [[TLS_FIELD:%.*]] = inttoptr i64 [[PTRI]] to ptr +; OPT-NEXT: [[V8A:%.*]] = load volatile i8, ptr [[TLS_FIELD]], align 8 +; OPT-NEXT: [[TLS1:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI2:%.*]] = add i64 [[TLS1]], 4095 +; OPT-NEXT: [[TLS_FIELD3:%.*]] = inttoptr i64 [[PTRI2]] to ptr +; OPT-NEXT: [[V8B:%.*]] = load volatile i8, ptr [[TLS_FIELD3]], align 8 +; OPT-NEXT: [[TLS4:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI5:%.*]] = add i64 [[TLS4]], -255 +; OPT-NEXT: [[TLS_FIELD6:%.*]] = inttoptr i64 [[PTRI5]] to ptr +; OPT-NEXT: [[V16A:%.*]] = load volatile i16, ptr [[TLS_FIELD6]], align 8 +; OPT-NEXT: [[TLS7:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI8:%.*]] = add i64 [[TLS7]], 8190 +; OPT-NEXT: [[TLS_FIELD9:%.*]] = inttoptr i64 [[PTRI8]] to ptr +; OPT-NEXT: [[V16B:%.*]] = load volatile i16, ptr [[TLS_FIELD9]], align 8 +; OPT-NEXT: [[TLS10:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI11:%.*]] = add i64 [[TLS10]], -255 +; OPT-NEXT: [[TLS_FIELD12:%.*]] = inttoptr i64 [[PTRI11]] to ptr +; OPT-NEXT: [[V32A:%.*]] = load volatile i32, ptr [[TLS_FIELD12]], align 8 +; OPT-NEXT: [[TLS13:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI14:%.*]] = add i64 [[TLS13]], 16380 +; OPT-NEXT: [[TLS_FIELD15:%.*]] = inttoptr i64 [[PTRI14]] to ptr +; OPT-NEXT: [[V32B:%.*]] = load volatile i32, ptr [[TLS_FIELD15]], align 8 +; OPT-NEXT: [[TLS16:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI17:%.*]] = add i64 [[TLS16]], -255 +; OPT-NEXT: [[TLS_FIELD18:%.*]] = inttoptr i64 [[PTRI17]] to ptr +; OPT-NEXT: [[V64A:%.*]] = load volatile i64, ptr [[TLS_FIELD18]], align 8 +; OPT-NEXT: [[TLS19:%.*]] = call i64 @llvm.read_register.i64(metadata [[META0]]) +; OPT-NEXT: [[PTRI20:%.*]] = add i64 [[TLS19]], 32760 +; OPT-NEXT: [[TLS_FIELD21:%.*]] = inttoptr i64 [[PTRI20]] to ptr +; OPT-NEXT: [[V64B:%.*]] = load volatile i64, ptr [[TLS_FIELD21]], align 8 + %v8a = load volatile i8 , ptr addrspace(255) inttoptr (i64 -255 to ptr addrspace(255)), align 8 + %v8b = load volatile i8 , ptr addrspace(255) inttoptr (i64 4095 to ptr addrspace(255)), align 8 + %v16a = load volatile i16 , ptr addrspace(255) inttoptr (i64 -255 to ptr addrspace(255)), align 8 + %v16b = load volatile i16 , ptr addrspace(255) inttoptr (i64 8190 to ptr addrspace(255)), align 8 + %v32a = load volatile i32 , ptr addrspace(255) inttoptr (i64 -255 to ptr addrspace(255)), align 8 + %v32b = load volatile i32 , ptr addrspace(255) inttoptr (i64 16380 to ptr addrspace(255)), align 8 + %v64a = load volatile i64 , ptr addrspace(255) inttoptr (i64 -255 to ptr addrspace(255)), align 8 + %v64b = load volatile i64 , ptr addrspace(255) inttoptr (i64 32760 to ptr addrspace(255)), align 8 + + ; just collect results + %x8 = icmp eq i8 %v8a, %v8b + %x16 = icmp eq i16 %v16a, %v16b + %x32 = icmp eq i32 %v32a, %v32b + %x64 = icmp eq i64 %v64a, %v64b + %y1 = xor i1 %x8, %x16 + %y2 = xor i1 %x32, %x64 + %y3 = xor i1 %y1, %y2 + + ret i1 %y3 +} + +; addrspace(255)* must not be cast to int but +; this case does not fail because LLVM parser translates it to "ret i64 816". +define i64 @cast-from-p255-to-i64() { +; OPT-LABEL: @cast-from-p255-to-i64 +; OPT-NEXT: ret i64 816 + ret i64 ptrtoint (ptr addrspace(255) inttoptr (i64 816 to ptr addrspace(255)) to i64) +} + +; No cast constraints for addrspace(257). +define void @cast-from-p257-to-i64() { +; OPT-LABEL: @cast-from-p257-to-i64 +; OPT-NEXT: ptrtoint + %v = ptrtoint ptr addrspace(257) null to i64 + ret void +} + +define void @cast-from-p257-to-p255() { +; OPT-LABEL: @cast-from-p257-to-p255 +; OPT-NEXT: addrspacecast + %v = addrspacecast ptr addrspace(257) null to ptr addrspace(255) + ret void +} +