OLD | NEW |
1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 "Infinite-weight Variable has no register assigned"); | 458 "Infinite-weight Variable has no register assigned"); |
459 } | 459 } |
460 int32_t Offset = Var->getStackOffset(); | 460 int32_t Offset = Var->getStackOffset(); |
461 int32_t BaseRegNum = Var->getBaseRegNum(); | 461 int32_t BaseRegNum = Var->getBaseRegNum(); |
462 if (BaseRegNum == Variable::NoRegister) { | 462 if (BaseRegNum == Variable::NoRegister) { |
463 BaseRegNum = getFrameOrStackReg(); | 463 BaseRegNum = getFrameOrStackReg(); |
464 if (!hasFramePointer()) | 464 if (!hasFramePointer()) |
465 Offset += getStackAdjustment(); | 465 Offset += getStackAdjustment(); |
466 } | 466 } |
467 const Type VarTy = Var->getType(); | 467 const Type VarTy = Var->getType(); |
468 if (!isLegalVariableStackOffset(VarTy, Offset)) { | 468 if (!isLegalMemOffset(VarTy, Offset)) { |
469 llvm::report_fatal_error("Illegal stack offset"); | 469 llvm::report_fatal_error("Illegal stack offset"); |
470 } | 470 } |
471 Str << "[" << getRegName(BaseRegNum, VarTy); | 471 Str << "[" << getRegName(BaseRegNum, VarTy); |
472 if (Offset != 0) { | 472 if (Offset != 0) { |
473 Str << ", " << getConstantPrefix() << Offset; | 473 Str << ", " << getConstantPrefix() << Offset; |
474 } | 474 } |
475 Str << "]"; | 475 Str << "]"; |
476 } | 476 } |
477 | 477 |
478 bool TargetARM32::CallingConv::I64InRegs(std::pair<int32_t, int32_t> *Regs) { | 478 bool TargetARM32::CallingConv::I64InRegs(std::pair<int32_t, int32_t> *Regs) { |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
830 finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, InArgsSizeBytes); | 830 finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, InArgsSizeBytes); |
831 } | 831 } |
832 | 832 |
833 // Fill in stack offsets for locals. | 833 // Fill in stack offsets for locals. |
834 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes, | 834 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes, |
835 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize, | 835 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize, |
836 UsesFramePointer); | 836 UsesFramePointer); |
837 this->HasComputedFrame = true; | 837 this->HasComputedFrame = true; |
838 | 838 |
839 if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) { | 839 if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) { |
840 OstreamLocker L(Func->getContext()); | 840 OstreamLocker _(Func->getContext()); |
841 Ostream &Str = Func->getContext()->getStrDump(); | 841 Ostream &Str = Func->getContext()->getStrDump(); |
842 | 842 |
843 Str << "Stack layout:\n"; | 843 Str << "Stack layout:\n"; |
844 uint32_t SPAdjustmentPaddingSize = | 844 uint32_t SPAdjustmentPaddingSize = |
845 SpillAreaSizeBytes - LocalsSpillAreaSize - | 845 SpillAreaSizeBytes - LocalsSpillAreaSize - |
846 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes; | 846 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes; |
847 Str << " in-args = " << InArgsSizeBytes << " bytes\n" | 847 Str << " in-args = " << InArgsSizeBytes << " bytes\n" |
848 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n" | 848 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n" |
849 << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n" | 849 << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n" |
850 << " globals spill area = " << GlobalsSize << " bytes\n" | 850 << " globals spill area = " << GlobalsSize << " bytes\n" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 Variable *RetValue = nullptr; | 940 Variable *RetValue = nullptr; |
941 if (RI->getSrcSize()) | 941 if (RI->getSrcSize()) |
942 RetValue = llvm::cast<Variable>(RI->getSrc(0)); | 942 RetValue = llvm::cast<Variable>(RI->getSrc(0)); |
943 _bundle_lock(); | 943 _bundle_lock(); |
944 _bic(LR, LR, RetMask); | 944 _bic(LR, LR, RetMask); |
945 _ret(LR, RetValue); | 945 _ret(LR, RetValue); |
946 _bundle_unlock(); | 946 _bundle_unlock(); |
947 RI->setDeleted(); | 947 RI->setDeleted(); |
948 } | 948 } |
949 | 949 |
950 bool TargetARM32::isLegalVariableStackOffset(Type Ty, int32_t Offset) const { | 950 bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const { |
951 constexpr bool SignExt = false; | 951 constexpr bool ZeroExt = false; |
952 return OperandARM32Mem::canHoldOffset(Ty, SignExt, Offset); | 952 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset); |
953 } | 953 } |
954 | 954 |
955 StackVariable *TargetARM32::legalizeVariableSlot(Variable *Var, | 955 Variable *TargetARM32::newBaseRegister(int32_t OriginalOffset, |
956 int32_t StackAdjust, | 956 int32_t StackAdjust, |
957 Variable *OrigBaseReg) { | 957 Variable *OrigBaseReg) { |
958 int32_t Offset = Var->getStackOffset() + StackAdjust; | 958 int32_t Offset = OriginalOffset + StackAdjust; |
959 // Legalize will likely need a movw/movt combination, but if the top bits are | 959 // Legalize will likely need a movw/movt combination, but if the top bits are |
960 // all 0 from negating the offset and subtracting, we could use that instead. | 960 // all 0 from negating the offset and subtracting, we could use that instead. |
961 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; | 961 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; |
962 if (ShouldSub) | 962 if (ShouldSub) |
963 Offset = -Offset; | 963 Offset = -Offset; |
964 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset), | 964 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset), |
965 Legal_Reg | Legal_Flex, getReservedTmpReg()); | 965 Legal_Reg | Legal_Flex, getReservedTmpReg()); |
966 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg()); | 966 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg()); |
967 if (ShouldSub) | 967 if (ShouldSub) |
968 _sub(ScratchReg, OrigBaseReg, OffsetVal); | 968 _sub(ScratchReg, OrigBaseReg, OffsetVal); |
969 else | 969 else |
970 _add(ScratchReg, OrigBaseReg, OffsetVal); | 970 _add(ScratchReg, OrigBaseReg, OffsetVal); |
971 StackVariable *NewVar = Func->makeVariable<StackVariable>(stackSlotType()); | 971 return ScratchReg; |
972 NewVar->setMustNotHaveReg(); | 972 } |
973 NewVar->setBaseRegNum(ScratchReg->getRegNum()); | 973 |
974 constexpr int32_t NewOffset = 0; | 974 StackVariable *TargetARM32::legalizeStackSlot(Type Ty, int32_t Offset, |
975 NewVar->setStackOffset(NewOffset); | 975 int32_t StackAdjust, |
976 return NewVar; | 976 Variable *OrigBaseReg, |
| 977 Variable **NewBaseReg, |
| 978 int32_t *NewBaseOffset) { |
| 979 if (*NewBaseReg == nullptr) { |
| 980 *NewBaseReg = newBaseRegister(Offset, StackAdjust, OrigBaseReg); |
| 981 *NewBaseOffset = Offset + StackAdjust; |
| 982 } |
| 983 |
| 984 int32_t OffsetDiff = Offset + StackAdjust - *NewBaseOffset; |
| 985 if (!isLegalMemOffset(Ty, OffsetDiff)) { |
| 986 *NewBaseReg = newBaseRegister(Offset, StackAdjust, OrigBaseReg); |
| 987 *NewBaseOffset = Offset + StackAdjust; |
| 988 OffsetDiff = 0; |
| 989 } |
| 990 |
| 991 StackVariable *NewDest = Func->makeVariable<StackVariable>(Ty); |
| 992 NewDest->setMustNotHaveReg(); |
| 993 NewDest->setBaseRegNum((*NewBaseReg)->getRegNum()); |
| 994 NewDest->setStackOffset(OffsetDiff); |
| 995 return NewDest; |
| 996 } |
| 997 |
| 998 void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr, |
| 999 int32_t StackAdjust, |
| 1000 Variable *OrigBaseReg, |
| 1001 Variable **NewBaseReg, |
| 1002 int32_t *NewBaseOffset) { |
| 1003 Variable *Dest = MovInstr->getDest(); |
| 1004 assert(Dest != nullptr); |
| 1005 Type DestTy = Dest->getType(); |
| 1006 assert(DestTy != IceType_i64); |
| 1007 |
| 1008 Operand *Src = MovInstr->getSrc(0); |
| 1009 Type SrcTy = Src->getType(); |
| 1010 assert(SrcTy != IceType_i64); |
| 1011 |
| 1012 if (MovInstr->isMultiDest() || MovInstr->isMultiSource()) |
| 1013 return; |
| 1014 |
| 1015 bool Legalized = false; |
| 1016 if (!Dest->hasReg()) { |
| 1017 assert(llvm::cast<Variable>(Src)->hasReg()); |
| 1018 const int32_t Offset = Dest->getStackOffset(); |
| 1019 if (!isLegalMemOffset(DestTy, Offset + StackAdjust)) { |
| 1020 Legalized = true; |
| 1021 Dest = legalizeStackSlot(DestTy, Offset, StackAdjust, OrigBaseReg, |
| 1022 NewBaseReg, NewBaseOffset); |
| 1023 } |
| 1024 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) { |
| 1025 if (!Var->hasReg()) { |
| 1026 const int32_t Offset = Var->getStackOffset(); |
| 1027 if (!isLegalMemOffset(SrcTy, Offset + StackAdjust)) { |
| 1028 Legalized = true; |
| 1029 Src = legalizeStackSlot(SrcTy, Offset, StackAdjust, OrigBaseReg, |
| 1030 NewBaseReg, NewBaseOffset); |
| 1031 } |
| 1032 } |
| 1033 } else if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Src)) { |
| 1034 if (ConstantInteger32 *OffsetOp = Mem->getOffset()) { |
| 1035 const int32_t Offset = OffsetOp->getValue(); |
| 1036 if (!isLegalMemOffset(SrcTy, Offset + StackAdjust)) { |
| 1037 assert(Mem->getBase()->hasReg()); |
| 1038 assert(Mem->getBase()->getRegNum() == (int32_t)getFrameOrStackReg()); |
| 1039 Legalized = true; |
| 1040 Src = legalizeStackSlot(SrcTy, Offset, StackAdjust, OrigBaseReg, |
| 1041 NewBaseReg, NewBaseOffset); |
| 1042 } |
| 1043 } |
| 1044 } |
| 1045 |
| 1046 if (Legalized) { |
| 1047 _mov(Dest, Src); |
| 1048 MovInstr->setDeleted(); |
| 1049 } |
977 } | 1050 } |
978 | 1051 |
979 void TargetARM32::legalizeStackSlots() { | 1052 void TargetARM32::legalizeStackSlots() { |
980 // If a stack variable's frame offset doesn't fit, convert from: | 1053 // If a stack variable's frame offset doesn't fit, convert from: |
981 // ldr X, OFF[SP] | 1054 // ldr X, OFF[SP] |
982 // to: | 1055 // to: |
983 // movw/movt TMP, OFF_PART | 1056 // movw/movt TMP, OFF_PART |
984 // add TMP, TMP, SP | 1057 // add TMP, TMP, SP |
985 // ldr X, OFF_MORE[TMP] | 1058 // ldr X, OFF_MORE[TMP] |
986 // | 1059 // |
987 // This is safe because we have reserved TMP, and add for ARM does not | 1060 // This is safe because we have reserved TMP, and add for ARM does not |
988 // clobber the flags register. | 1061 // clobber the flags register. |
989 Func->dump("Before legalizeStackSlots"); | 1062 Func->dump("Before legalizeStackSlots"); |
990 assert(hasComputedFrame()); | 1063 assert(hasComputedFrame()); |
991 // Early exit, if SpillAreaSizeBytes is really small. | 1064 // Early exit, if SpillAreaSizeBytes is really small. |
992 // TODO(jpp): this is not safe -- loads and stores of q registers can't have | 1065 // TODO(jpp): this is not safe -- loads and stores of q registers can't have |
993 // offsets. | 1066 // offsets. |
994 if (isLegalVariableStackOffset(IceType_v4i32, SpillAreaSizeBytes)) | 1067 if (isLegalMemOffset(IceType_v4i32, SpillAreaSizeBytes)) |
995 return; | 1068 return; |
996 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); | 1069 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); |
997 int32_t StackAdjust = 0; | 1070 int32_t StackAdjust = 0; |
998 // Do a fairly naive greedy clustering for now. Pick the first stack slot | 1071 // Do a fairly naive greedy clustering for now. Pick the first stack slot |
999 // that's out of bounds and make a new base reg using the architecture's temp | 1072 // that's out of bounds and make a new base reg using the architecture's temp |
1000 // register. If that works for the next slot, then great. Otherwise, create a | 1073 // register. If that works for the next slot, then great. Otherwise, create a |
1001 // new base register, clobbering the previous base register. Never share a | 1074 // new base register, clobbering the previous base register. Never share a |
1002 // base reg across different basic blocks. This isn't ideal if local and | 1075 // base reg across different basic blocks. This isn't ideal if local and |
1003 // multi-block variables are far apart and their references are interspersed. | 1076 // multi-block variables are far apart and their references are interspersed. |
1004 // It may help to be more coordinated about assign stack slot numbers and may | 1077 // It may help to be more coordinated about assign stack slot numbers and may |
1005 // help to assign smaller offsets to higher-weight variables so that they | 1078 // help to assign smaller offsets to higher-weight variables so that they |
1006 // don't depend on this legalization. | 1079 // don't depend on this legalization. |
1007 for (CfgNode *Node : Func->getNodes()) { | 1080 for (CfgNode *Node : Func->getNodes()) { |
1008 Context.init(Node); | 1081 Context.init(Node); |
1009 StackVariable *NewBaseReg = nullptr; | 1082 Variable *NewBaseReg = nullptr; |
1010 int32_t NewBaseOffset = 0; | 1083 int32_t NewBaseOffset = 0; |
1011 while (!Context.atEnd()) { | 1084 while (!Context.atEnd()) { |
1012 PostIncrLoweringContext PostIncrement(Context); | 1085 PostIncrLoweringContext PostIncrement(Context); |
1013 Inst *CurInstr = Context.getCur(); | 1086 Inst *CurInstr = Context.getCur(); |
1014 Variable *Dest = CurInstr->getDest(); | 1087 Variable *Dest = CurInstr->getDest(); |
| 1088 |
1015 // Check if the previous NewBaseReg is clobbered, and reset if needed. | 1089 // Check if the previous NewBaseReg is clobbered, and reset if needed. |
1016 if ((Dest && NewBaseReg && Dest->hasReg() && | 1090 if ((Dest && NewBaseReg && Dest->hasReg() && |
1017 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) || | 1091 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) || |
1018 llvm::isa<InstFakeKill>(CurInstr)) { | 1092 llvm::isa<InstFakeKill>(CurInstr)) { |
1019 NewBaseReg = nullptr; | 1093 NewBaseReg = nullptr; |
1020 NewBaseOffset = 0; | 1094 NewBaseOffset = 0; |
1021 } | 1095 } |
| 1096 |
1022 // The stack adjustment only matters if we are using SP instead of FP. | 1097 // The stack adjustment only matters if we are using SP instead of FP. |
1023 if (!hasFramePointer()) { | 1098 if (!hasFramePointer()) { |
1024 if (auto *AdjInst = llvm::dyn_cast<InstARM32AdjustStack>(CurInstr)) { | 1099 if (auto *AdjInst = llvm::dyn_cast<InstARM32AdjustStack>(CurInstr)) { |
1025 StackAdjust += AdjInst->getAmount(); | 1100 StackAdjust += AdjInst->getAmount(); |
1026 NewBaseOffset += AdjInst->getAmount(); | 1101 NewBaseOffset += AdjInst->getAmount(); |
1027 continue; | 1102 continue; |
1028 } | 1103 } |
1029 if (llvm::isa<InstARM32Call>(CurInstr)) { | 1104 if (llvm::isa<InstARM32Call>(CurInstr)) { |
1030 NewBaseOffset -= StackAdjust; | 1105 NewBaseOffset -= StackAdjust; |
1031 StackAdjust = 0; | 1106 StackAdjust = 0; |
1032 continue; | 1107 continue; |
1033 } | 1108 } |
1034 } | 1109 } |
1035 | 1110 |
1036 // For now, only Mov instructions can have stack variables. We need to | 1111 // The Lowering ensures that ldr and str always have legal Mem operands. |
1037 // know the type of instruction because we currently create a fresh one | 1112 // The only other instruction that may access memory is mov. |
1038 // to replace Dest/Source, rather than mutate in place. | |
1039 bool MayNeedOffsetRewrite = false; | |
1040 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { | 1113 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { |
1041 MayNeedOffsetRewrite = | 1114 legalizeMovStackAddrImm(MovInstr, StackAdjust, OrigBaseReg, &NewBaseReg, |
1042 !MovInstr->isMultiDest() && !MovInstr->isMultiSource(); | 1115 &NewBaseOffset); |
1043 } | |
1044 | |
1045 if (!MayNeedOffsetRewrite) { | |
1046 continue; | |
1047 } | |
1048 | |
1049 assert(Dest != nullptr); | |
1050 Type DestTy = Dest->getType(); | |
1051 assert(DestTy != IceType_i64); | |
1052 if (!Dest->hasReg()) { | |
1053 int32_t Offset = Dest->getStackOffset(); | |
1054 Offset += StackAdjust; | |
1055 if (!isLegalVariableStackOffset(DestTy, Offset)) { | |
1056 if (NewBaseReg) { | |
1057 int32_t OffsetDiff = Offset - NewBaseOffset; | |
1058 if (isLegalVariableStackOffset(DestTy, OffsetDiff)) { | |
1059 StackVariable *NewDest = | |
1060 Func->makeVariable<StackVariable>(stackSlotType()); | |
1061 NewDest->setMustNotHaveReg(); | |
1062 NewDest->setBaseRegNum(NewBaseReg->getBaseRegNum()); | |
1063 NewDest->setStackOffset(OffsetDiff); | |
1064 Variable *NewDestVar = NewDest; | |
1065 _mov(NewDestVar, CurInstr->getSrc(0)); | |
1066 CurInstr->setDeleted(); | |
1067 continue; | |
1068 } | |
1069 } | |
1070 StackVariable *LegalDest = | |
1071 legalizeVariableSlot(Dest, StackAdjust, OrigBaseReg); | |
1072 assert(LegalDest != Dest); | |
1073 Variable *LegalDestVar = LegalDest; | |
1074 _mov(LegalDestVar, CurInstr->getSrc(0)); | |
1075 CurInstr->setDeleted(); | |
1076 NewBaseReg = LegalDest; | |
1077 NewBaseOffset = Offset; | |
1078 continue; | |
1079 } | |
1080 } | |
1081 assert(CurInstr->getSrcSize() == 1); | |
1082 Variable *Var = llvm::dyn_cast<Variable>(CurInstr->getSrc(0)); | |
1083 if (Var && !Var->hasReg()) { | |
1084 Type VarTy = Var->getType(); | |
1085 int32_t Offset = Var->getStackOffset(); | |
1086 Offset += StackAdjust; | |
1087 if (!isLegalVariableStackOffset(VarTy, Offset)) { | |
1088 if (NewBaseReg) { | |
1089 int32_t OffsetDiff = Offset - NewBaseOffset; | |
1090 if (isLegalVariableStackOffset(VarTy, OffsetDiff)) { | |
1091 StackVariable *NewVar = | |
1092 Func->makeVariable<StackVariable>(stackSlotType()); | |
1093 NewVar->setMustNotHaveReg(); | |
1094 NewVar->setBaseRegNum(NewBaseReg->getBaseRegNum()); | |
1095 NewVar->setStackOffset(OffsetDiff); | |
1096 _mov(Dest, NewVar); | |
1097 CurInstr->setDeleted(); | |
1098 continue; | |
1099 } | |
1100 } | |
1101 StackVariable *LegalVar = | |
1102 legalizeVariableSlot(Var, StackAdjust, OrigBaseReg); | |
1103 assert(LegalVar != Var); | |
1104 _mov(Dest, LegalVar); | |
1105 CurInstr->setDeleted(); | |
1106 NewBaseReg = LegalVar; | |
1107 NewBaseOffset = Offset; | |
1108 continue; | |
1109 } | |
1110 } | 1116 } |
1111 } | 1117 } |
1112 } | 1118 } |
1113 } | 1119 } |
1114 | 1120 |
1115 Operand *TargetARM32::loOperand(Operand *Operand) { | 1121 Operand *TargetARM32::loOperand(Operand *Operand) { |
1116 assert(Operand->getType() == IceType_i64); | 1122 assert(Operand->getType() == IceType_i64); |
1117 if (Operand->getType() != IceType_i64) | 1123 if (Operand->getType() != IceType_i64) |
1118 return Operand; | 1124 return Operand; |
1119 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) | 1125 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase, | 1170 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase, |
1165 Base, Four)); | 1171 Base, Four)); |
1166 return OperandARM32Mem::create(Func, SplitType, NewBase, Mem->getIndex(), | 1172 return OperandARM32Mem::create(Func, SplitType, NewBase, Mem->getIndex(), |
1167 Mem->getShiftOp(), Mem->getShiftAmt(), | 1173 Mem->getShiftOp(), Mem->getShiftAmt(), |
1168 Mem->getAddrMode()); | 1174 Mem->getAddrMode()); |
1169 } else { | 1175 } else { |
1170 Variable *Base = Mem->getBase(); | 1176 Variable *Base = Mem->getBase(); |
1171 ConstantInteger32 *Offset = Mem->getOffset(); | 1177 ConstantInteger32 *Offset = Mem->getOffset(); |
1172 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4)); | 1178 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4)); |
1173 int32_t NextOffsetVal = Offset->getValue() + 4; | 1179 int32_t NextOffsetVal = Offset->getValue() + 4; |
1174 const bool SignExt = false; | 1180 constexpr bool ZeroExt = false; |
1175 if (!OperandARM32Mem::canHoldOffset(SplitType, SignExt, NextOffsetVal)) { | 1181 if (!OperandARM32Mem::canHoldOffset(SplitType, ZeroExt, NextOffsetVal)) { |
1176 // We have to make a temp variable and add 4 to either Base or Offset. | 1182 // We have to make a temp variable and add 4 to either Base or Offset. |
1177 // If we add 4 to Offset, this will convert a non-RegReg addressing | 1183 // If we add 4 to Offset, this will convert a non-RegReg addressing |
1178 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows | 1184 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows |
1179 // RegReg addressing modes, prefer adding to base and replacing | 1185 // RegReg addressing modes, prefer adding to base and replacing |
1180 // instead. Thus we leave the old offset alone. | 1186 // instead. Thus we leave the old offset alone. |
1181 Constant *Four = Ctx->getConstantInt32(4); | 1187 Constant *Four = Ctx->getConstantInt32(4); |
1182 Variable *NewBase = Func->makeVariable(Base->getType()); | 1188 Variable *NewBase = Func->makeVariable(Base->getType()); |
1183 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, | 1189 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, |
1184 NewBase, Base, Four)); | 1190 NewBase, Base, Four)); |
1185 Base = NewBase; | 1191 Base = NewBase; |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1812 if (Instr->isUnconditional()) { | 1818 if (Instr->isUnconditional()) { |
1813 _br(Instr->getTargetUnconditional()); | 1819 _br(Instr->getTargetUnconditional()); |
1814 return; | 1820 return; |
1815 } | 1821 } |
1816 Operand *Cond = Instr->getCondition(); | 1822 Operand *Cond = Instr->getCondition(); |
1817 | 1823 |
1818 CondARM32::Cond BrCondTrue0 = CondARM32::NE; | 1824 CondARM32::Cond BrCondTrue0 = CondARM32::NE; |
1819 CondARM32::Cond BrCondTrue1 = CondARM32::kNone; | 1825 CondARM32::Cond BrCondTrue1 = CondARM32::kNone; |
1820 CondARM32::Cond BrCondFalse = CondARM32::kNone; | 1826 CondARM32::Cond BrCondFalse = CondARM32::kNone; |
1821 if (!_mov_i1_to_flags(Cond, &BrCondTrue0, &BrCondTrue1, &BrCondFalse)) { | 1827 if (!_mov_i1_to_flags(Cond, &BrCondTrue0, &BrCondTrue1, &BrCondFalse)) { |
1822 // "Cond" was not fold. | 1828 // "Cond" was not folded. |
1823 Type Ty = Cond->getType(); | 1829 Type Ty = Cond->getType(); |
1824 Variable *Src0R = legalizeToReg(Cond); | 1830 Variable *Src0R = legalizeToReg(Cond); |
1825 assert(Ty == IceType_i1); | 1831 assert(Ty == IceType_i1); |
1826 if (Ty != IceType_i32) | 1832 if (Ty != IceType_i32) |
1827 _uxt(Src0R, Src0R); | 1833 _uxt(Src0R, Src0R); |
1828 Constant *_0 = Ctx->getConstantZero(IceType_i32); | 1834 Constant *_0 = Ctx->getConstantZero(IceType_i32); |
1829 _cmp(Src0R, _0); | 1835 _cmp(Src0R, _0); |
1830 BrCondTrue0 = CondARM32::NE; | 1836 BrCondTrue0 = CondARM32::NE; |
1831 } | 1837 } |
1832 | 1838 |
(...skipping 1535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3368 Type Ty = Load->getDest()->getType(); | 3374 Type Ty = Load->getDest()->getType(); |
3369 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); | 3375 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); |
3370 Variable *DestLoad = Load->getDest(); | 3376 Variable *DestLoad = Load->getDest(); |
3371 | 3377 |
3372 // TODO(jvoung): handled folding opportunities. Sign and zero extension can | 3378 // TODO(jvoung): handled folding opportunities. Sign and zero extension can |
3373 // be folded into a load. | 3379 // be folded into a load. |
3374 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0); | 3380 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0); |
3375 lowerAssign(Assign); | 3381 lowerAssign(Assign); |
3376 } | 3382 } |
3377 | 3383 |
3378 void TargetARM32::doAddressOptLoad() {} | 3384 namespace { |
| 3385 void dumpAddressOpt(const Cfg *Func, const Variable *Base, int32_t Offset, |
| 3386 const Variable *OffsetReg, int16_t OffsetRegShAmt, |
| 3387 const Inst *Reason) { |
| 3388 if (!BuildDefs::dump()) |
| 3389 return; |
| 3390 if (!Func->isVerbose(IceV_AddrOpt)) |
| 3391 return; |
| 3392 OstreamLocker _(Func->getContext()); |
| 3393 Ostream &Str = Func->getContext()->getStrDump(); |
| 3394 Str << "Instruction: "; |
| 3395 Reason->dumpDecorated(Func); |
| 3396 Str << " results in Base="; |
| 3397 if (Base) |
| 3398 Base->dump(Func); |
| 3399 else |
| 3400 Str << "<null>"; |
| 3401 Str << ", OffsetReg="; |
| 3402 if (OffsetReg) |
| 3403 OffsetReg->dump(Func); |
| 3404 else |
| 3405 Str << "<null>"; |
| 3406 Str << ", Shift=" << OffsetRegShAmt << ", Offset=" << Offset << "\n"; |
| 3407 } |
| 3408 |
| 3409 bool matchAssign(const VariablesMetadata *VMetadata, Variable **Var, |
| 3410 int32_t *Offset, const Inst **Reason) { |
| 3411 // Var originates from Var=SrcVar ==> set Var:=SrcVar |
| 3412 if (*Var == nullptr) |
| 3413 return false; |
| 3414 const Inst *VarAssign = VMetadata->getSingleDefinition(*Var); |
| 3415 if (!VarAssign) |
| 3416 return false; |
| 3417 assert(!VMetadata->isMultiDef(*Var)); |
| 3418 if (!llvm::isa<InstAssign>(VarAssign)) |
| 3419 return false; |
| 3420 |
| 3421 Operand *SrcOp = VarAssign->getSrc(0); |
| 3422 if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) { |
| 3423 if (!VMetadata->isMultiDef(SrcVar) || |
| 3424 // TODO: ensure SrcVar stays single-BB |
| 3425 false) { |
| 3426 *Var = SrcVar; |
| 3427 } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { |
| 3428 int32_t MoreOffset = Const->getValue(); |
| 3429 int32_t NewOffset = MoreOffset + *Offset; |
| 3430 if (Utils::WouldOverflowAdd(*Offset, MoreOffset)) |
| 3431 return false; |
| 3432 *Var = nullptr; |
| 3433 *Offset += NewOffset; |
| 3434 } |
| 3435 |
| 3436 *Reason = VarAssign; |
| 3437 return true; |
| 3438 } |
| 3439 |
| 3440 return false; |
| 3441 } |
| 3442 |
| 3443 bool isAddOrSub(const Inst *Inst, InstArithmetic::OpKind *Kind) { |
| 3444 if (const auto *Arith = llvm::dyn_cast<InstArithmetic>(Inst)) { |
| 3445 switch (Arith->getOp()) { |
| 3446 default: |
| 3447 return false; |
| 3448 case InstArithmetic::Add: |
| 3449 case InstArithmetic::Sub: |
| 3450 *Kind = Arith->getOp(); |
| 3451 return true; |
| 3452 } |
| 3453 } |
| 3454 return false; |
| 3455 } |
| 3456 |
| 3457 bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, Variable **Base, |
| 3458 Variable **OffsetReg, int32_t OffsetRegShamt, |
| 3459 const Inst **Reason) { |
| 3460 // OffsetReg==nullptr && Base is Base=Var1+Var2 ==> |
| 3461 // set Base=Var1, OffsetReg=Var2, Shift=0 |
| 3462 if (*Base == nullptr) |
| 3463 return false; |
| 3464 if (*OffsetReg != nullptr) |
| 3465 return false; |
| 3466 (void)OffsetRegShamt; |
| 3467 assert(OffsetRegShamt == 0); |
| 3468 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base); |
| 3469 if (BaseInst == nullptr) |
| 3470 return false; |
| 3471 assert(!VMetadata->isMultiDef(*Base)); |
| 3472 if (BaseInst->getSrcSize() < 2) |
| 3473 return false; |
| 3474 auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0)); |
| 3475 if (!Var1) |
| 3476 return false; |
| 3477 if (VMetadata->isMultiDef(Var1)) |
| 3478 return false; |
| 3479 auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1)); |
| 3480 if (!Var2) |
| 3481 return false; |
| 3482 if (VMetadata->isMultiDef(Var2)) |
| 3483 return false; |
| 3484 InstArithmetic::OpKind _; |
| 3485 if (!isAddOrSub(BaseInst, &_) || |
| 3486 // TODO: ensure Var1 and Var2 stay single-BB |
| 3487 false) |
| 3488 return false; |
| 3489 *Base = Var1; |
| 3490 *OffsetReg = Var2; |
| 3491 // OffsetRegShamt is already 0. |
| 3492 *Reason = BaseInst; |
| 3493 return true; |
| 3494 } |
| 3495 |
| 3496 bool matchShiftedOffsetReg(const VariablesMetadata *VMetadata, |
| 3497 Variable **OffsetReg, OperandARM32::ShiftKind *Kind, |
| 3498 int32_t *OffsetRegShamt, const Inst **Reason) { |
| 3499 // OffsetReg is OffsetReg=Var*Const && log2(Const)+Shift<=32 ==> |
| 3500 // OffsetReg=Var, Shift+=log2(Const) |
| 3501 // OffsetReg is OffsetReg=Var<<Const && Const+Shift<=32 ==> |
| 3502 // OffsetReg=Var, Shift+=Const |
| 3503 // OffsetReg is OffsetReg=Var>>Const && Const-Shift>=-32 ==> |
| 3504 // OffsetReg=Var, Shift-=Const |
| 3505 OperandARM32::ShiftKind NewShiftKind = OperandARM32::kNoShift; |
| 3506 if (*OffsetReg == nullptr) |
| 3507 return false; |
| 3508 auto *IndexInst = VMetadata->getSingleDefinition(*OffsetReg); |
| 3509 if (IndexInst == nullptr) |
| 3510 return false; |
| 3511 assert(!VMetadata->isMultiDef(*OffsetReg)); |
| 3512 if (IndexInst->getSrcSize() < 2) |
| 3513 return false; |
| 3514 auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst); |
| 3515 if (ArithInst == nullptr) |
| 3516 return false; |
| 3517 auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0)); |
| 3518 if (Var == nullptr) |
| 3519 return false; |
| 3520 auto *Const = llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1)); |
| 3521 if (Const == nullptr) { |
| 3522 assert(!llvm::isa<ConstantInteger32>(ArithInst->getSrc(0))); |
| 3523 return false; |
| 3524 } |
| 3525 if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) |
| 3526 return false; |
| 3527 |
| 3528 uint32_t NewShamt = -1; |
| 3529 switch (ArithInst->getOp()) { |
| 3530 default: |
| 3531 return false; |
| 3532 case InstArithmetic::Shl: { |
| 3533 NewShiftKind = OperandARM32::LSL; |
| 3534 NewShamt = Const->getValue(); |
| 3535 if (NewShamt > 31) |
| 3536 return false; |
| 3537 } break; |
| 3538 case InstArithmetic::Lshr: { |
| 3539 NewShiftKind = OperandARM32::LSR; |
| 3540 NewShamt = Const->getValue(); |
| 3541 if (NewShamt > 31) |
| 3542 return false; |
| 3543 } break; |
| 3544 case InstArithmetic::Ashr: { |
| 3545 NewShiftKind = OperandARM32::ASR; |
| 3546 NewShamt = Const->getValue(); |
| 3547 if (NewShamt > 31) |
| 3548 return false; |
| 3549 } break; |
| 3550 case InstArithmetic::Udiv: |
| 3551 case InstArithmetic::Mul: { |
| 3552 const uint32_t UnsignedConst = Const->getValue(); |
| 3553 NewShamt = llvm::findFirstSet(UnsignedConst); |
| 3554 if (NewShamt != llvm::findLastSet(UnsignedConst)) { |
| 3555 // First bit set is not the same as the last bit set, so Const is not |
| 3556 // a power of 2. |
| 3557 return false; |
| 3558 } |
| 3559 NewShiftKind = ArithInst->getOp() == InstArithmetic::Udiv |
| 3560 ? OperandARM32::LSR |
| 3561 : OperandARM32::LSL; |
| 3562 } break; |
| 3563 } |
| 3564 // Allowed "transitions": |
| 3565 // kNoShift -> * iff NewShamt < 31 |
| 3566 // LSL -> LSL iff NewShamt + OffsetRegShamt < 31 |
| 3567 // LSR -> LSR iff NewShamt + OffsetRegShamt < 31 |
| 3568 // ASR -> ASR iff NewShamt + OffsetRegShamt < 31 |
| 3569 if (*Kind != OperandARM32::kNoShift && *Kind != NewShiftKind) { |
| 3570 return false; |
| 3571 } |
| 3572 const int32_t NewOffsetRegShamt = *OffsetRegShamt + NewShamt; |
| 3573 if (NewOffsetRegShamt > 31) |
| 3574 return false; |
| 3575 *OffsetReg = Var; |
| 3576 *OffsetRegShamt = NewOffsetRegShamt; |
| 3577 *Kind = NewShiftKind; |
| 3578 *Reason = IndexInst; |
| 3579 return true; |
| 3580 } |
| 3581 |
| 3582 bool matchOffsetBase(const VariablesMetadata *VMetadata, Variable **Base, |
| 3583 int32_t *Offset, const Inst **Reason) { |
| 3584 // Base is Base=Var+Const || Base is Base=Const+Var ==> |
| 3585 // set Base=Var, Offset+=Const |
| 3586 // Base is Base=Var-Const ==> |
| 3587 // set Base=Var, Offset-=Const |
| 3588 if (*Base == nullptr) |
| 3589 return false; |
| 3590 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base); |
| 3591 if (BaseInst == nullptr) { |
| 3592 return false; |
| 3593 } |
| 3594 assert(!VMetadata->isMultiDef(*Base)); |
| 3595 |
| 3596 auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst); |
| 3597 if (ArithInst == nullptr) |
| 3598 return false; |
| 3599 InstArithmetic::OpKind Kind; |
| 3600 if (!isAddOrSub(ArithInst, &Kind)) |
| 3601 return false; |
| 3602 bool IsAdd = Kind == InstArithmetic::Add; |
| 3603 Operand *Src0 = ArithInst->getSrc(0); |
| 3604 Operand *Src1 = ArithInst->getSrc(1); |
| 3605 auto *Var0 = llvm::dyn_cast<Variable>(Src0); |
| 3606 auto *Var1 = llvm::dyn_cast<Variable>(Src1); |
| 3607 auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0); |
| 3608 auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1); |
| 3609 Variable *NewBase = nullptr; |
| 3610 int32_t NewOffset = *Offset; |
| 3611 |
| 3612 if (Var0 == nullptr && Const0 == nullptr) { |
| 3613 assert(llvm::isa<ConstantRelocatable>(Src0)); |
| 3614 return false; |
| 3615 } |
| 3616 |
| 3617 if (Var1 == nullptr && Const1 == nullptr) { |
| 3618 assert(llvm::isa<ConstantRelocatable>(Src1)); |
| 3619 return false; |
| 3620 } |
| 3621 |
| 3622 if (Var0 && Var1) |
| 3623 // TODO(jpp): merge base/index splitting into here. |
| 3624 return false; |
| 3625 if (!IsAdd && Var1) |
| 3626 return false; |
| 3627 if (Var0) |
| 3628 NewBase = Var0; |
| 3629 else if (Var1) |
| 3630 NewBase = Var1; |
| 3631 // Compute the updated constant offset. |
| 3632 if (Const0) { |
| 3633 int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue(); |
| 3634 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
| 3635 return false; |
| 3636 NewOffset += MoreOffset; |
| 3637 } |
| 3638 if (Const1) { |
| 3639 int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue(); |
| 3640 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
| 3641 return false; |
| 3642 NewOffset += MoreOffset; |
| 3643 } |
| 3644 |
| 3645 // Update the computed address parameters once we are sure optimization |
| 3646 // is valid. |
| 3647 *Base = NewBase; |
| 3648 *Offset = NewOffset; |
| 3649 *Reason = BaseInst; |
| 3650 return true; |
| 3651 } |
| 3652 } // end of anonymous namespace |
| 3653 |
| 3654 // ARM32 address modes: |
| 3655 // ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12], |
| 3656 // [reg +/- reg << shamt5] |
| 3657 // ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8] |
| 3658 // ld/st vectors : [reg] |
| 3659 // |
| 3660 // For now, we don't handle address modes with Relocatables. |
| 3661 namespace { |
| 3662 // MemTraits contains per-type valid address mode information. |
| 3663 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ |
| 3664 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag); |
| 3665 ICETYPEARM32_TABLE |
| 3666 #undef X |
| 3667 |
| 3668 static const struct { |
| 3669 int32_t ValidImmMask; |
| 3670 bool CanHaveImm; |
| 3671 bool CanHaveIndex; |
| 3672 bool CanHaveShiftedIndex; |
| 3673 } MemTraits[] = { |
| 3674 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ |
| 3675 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \ |
| 3676 , |
| 3677 ICETYPEARM32_TABLE |
| 3678 #undef X |
| 3679 }; |
| 3680 static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits); |
| 3681 } // end of anonymous namespace |
| 3682 |
| 3683 OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func, |
| 3684 const Inst *LdSt, |
| 3685 Operand *Base) { |
| 3686 assert(Base != nullptr); |
| 3687 int32_t OffsetImm = 0; |
| 3688 Variable *OffsetReg = nullptr; |
| 3689 int32_t OffsetRegShamt = 0; |
| 3690 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift; |
| 3691 |
| 3692 Func->resetCurrentNode(); |
| 3693 if (Func->isVerbose(IceV_AddrOpt)) { |
| 3694 OstreamLocker _(Func->getContext()); |
| 3695 Ostream &Str = Func->getContext()->getStrDump(); |
| 3696 Str << "\nAddress mode formation:\t"; |
| 3697 LdSt->dumpDecorated(Func); |
| 3698 } |
| 3699 |
| 3700 if (isVectorType(Ty)) |
| 3701 // vector loads and stores do not allow offsets, and only support the |
| 3702 // "[reg]" addressing mode (the other supported modes are write back.) |
| 3703 return nullptr; |
| 3704 |
| 3705 auto *BaseVar = llvm::dyn_cast<Variable>(Base); |
| 3706 if (BaseVar == nullptr) |
| 3707 return nullptr; |
| 3708 |
| 3709 (void)MemTraitsSize; |
| 3710 assert(Ty < MemTraitsSize); |
| 3711 auto *TypeTraits = &MemTraits[Ty]; |
| 3712 const bool CanHaveIndex = TypeTraits->CanHaveIndex; |
| 3713 const bool CanHaveShiftedIndex = TypeTraits->CanHaveShiftedIndex; |
| 3714 const bool CanHaveImm = TypeTraits->CanHaveImm; |
| 3715 const int32_t ValidImmMask = TypeTraits->ValidImmMask; |
| 3716 (void)ValidImmMask; |
| 3717 assert(!CanHaveImm || ValidImmMask >= 0); |
| 3718 |
| 3719 const VariablesMetadata *VMetadata = Func->getVMetadata(); |
| 3720 const Inst *Reason = nullptr; |
| 3721 |
| 3722 do { |
| 3723 if (Reason != nullptr) { |
| 3724 dumpAddressOpt(Func, BaseVar, OffsetImm, OffsetReg, OffsetRegShamt, |
| 3725 Reason); |
| 3726 Reason = nullptr; |
| 3727 } |
| 3728 |
| 3729 if (matchAssign(VMetadata, &BaseVar, &OffsetImm, &Reason)) { |
| 3730 continue; |
| 3731 } |
| 3732 |
| 3733 if (CanHaveIndex && |
| 3734 matchAssign(VMetadata, &OffsetReg, &OffsetImm, &Reason)) { |
| 3735 continue; |
| 3736 } |
| 3737 |
| 3738 if (CanHaveIndex && matchCombinedBaseIndex(VMetadata, &BaseVar, &OffsetReg, |
| 3739 OffsetRegShamt, &Reason)) { |
| 3740 continue; |
| 3741 } |
| 3742 |
| 3743 if (CanHaveShiftedIndex) { |
| 3744 if (matchShiftedOffsetReg(VMetadata, &OffsetReg, &ShiftKind, |
| 3745 &OffsetRegShamt, &Reason)) { |
| 3746 continue; |
| 3747 } |
| 3748 |
| 3749 if ((OffsetRegShamt == 0) && |
| 3750 matchShiftedOffsetReg(VMetadata, &BaseVar, &ShiftKind, |
| 3751 &OffsetRegShamt, &Reason)) { |
| 3752 std::swap(BaseVar, OffsetReg); |
| 3753 continue; |
| 3754 } |
| 3755 } |
| 3756 |
| 3757 if (matchOffsetBase(VMetadata, &BaseVar, &OffsetImm, &Reason)) { |
| 3758 continue; |
| 3759 } |
| 3760 } while (Reason); |
| 3761 |
| 3762 if (BaseVar == nullptr) { |
| 3763 // [OffsetReg{, LSL Shamt}{, #OffsetImm}] is not legal in ARM, so we have to |
| 3764 // legalize the addressing mode to [BaseReg, OffsetReg{, LSL Shamt}]. |
| 3765 // Instead of a zeroed BaseReg, we initialize it with OffsetImm: |
| 3766 // |
| 3767 // [OffsetReg{, LSL Shamt}{, #OffsetImm}] -> |
| 3768 // mov BaseReg, #OffsetImm |
| 3769 // use of [BaseReg, OffsetReg{, LSL Shamt}] |
| 3770 // |
| 3771 const Type PointerType = getPointerType(); |
| 3772 BaseVar = makeReg(PointerType); |
| 3773 Context.insert( |
| 3774 InstAssign::create(Func, BaseVar, Ctx->getConstantInt32(OffsetImm))); |
| 3775 OffsetImm = 0; |
| 3776 } else if (OffsetImm != 0) { |
| 3777 // ARM Ldr/Str instructions have limited range immediates. The formation |
| 3778 // loop above materialized an Immediate carelessly, so we ensure the |
| 3779 // generated offset is sane. |
| 3780 const int32_t PositiveOffset = OffsetImm > 0 ? OffsetImm : -OffsetImm; |
| 3781 const InstArithmetic::OpKind Op = |
| 3782 OffsetImm > 0 ? InstArithmetic::Add : InstArithmetic::Sub; |
| 3783 |
| 3784 if (!CanHaveImm || !isLegalMemOffset(Ty, OffsetImm) || |
| 3785 OffsetReg != nullptr) { |
| 3786 if (OffsetReg == nullptr) { |
| 3787 // We formed a [Base, #const] addressing mode which is not encodable in |
| 3788 // ARM. There is little point in forming an address mode now if we don't |
| 3789 // have an offset. Effectively, we would end up with something like |
| 3790 // |
| 3791 // [Base, #const] -> add T, Base, #const |
| 3792 // use of [T] |
| 3793 // |
| 3794 // Which is exactly what we already have. So we just bite the bullet |
| 3795 // here and don't form any address mode. |
| 3796 return nullptr; |
| 3797 } |
| 3798 // We formed [Base, Offset {, LSL Amnt}, #const]. Oops. Legalize it to |
| 3799 // |
| 3800 // [Base, Offset, {LSL amount}, #const] -> |
| 3801 // add T, Base, #const |
| 3802 // use of [T, Offset {, LSL amount}] |
| 3803 const Type PointerType = getPointerType(); |
| 3804 Variable *T = makeReg(PointerType); |
| 3805 Context.insert(InstArithmetic::create( |
| 3806 Func, Op, T, BaseVar, Ctx->getConstantInt32(PositiveOffset))); |
| 3807 BaseVar = T; |
| 3808 OffsetImm = 0; |
| 3809 } |
| 3810 } |
| 3811 |
| 3812 assert(BaseVar != nullptr); |
| 3813 assert(OffsetImm == 0 || OffsetReg == nullptr); |
| 3814 assert(OffsetReg == nullptr || CanHaveIndex); |
| 3815 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm |
| 3816 : (ValidImmMask & OffsetImm) == OffsetImm); |
| 3817 |
| 3818 if (OffsetReg != nullptr) { |
| 3819 return OperandARM32Mem::create(Func, Ty, BaseVar, OffsetReg, ShiftKind, |
| 3820 OffsetRegShamt); |
| 3821 } |
| 3822 |
| 3823 return OperandARM32Mem::create( |
| 3824 Func, Ty, BaseVar, |
| 3825 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm))); |
| 3826 } |
| 3827 |
| 3828 void TargetARM32::doAddressOptLoad() { |
| 3829 Inst *Instr = Context.getCur(); |
| 3830 assert(llvm::isa<InstLoad>(Instr)); |
| 3831 Variable *Dest = Instr->getDest(); |
| 3832 Operand *Addr = Instr->getSrc(0); |
| 3833 if (OperandARM32Mem *Mem = |
| 3834 formAddressingMode(Dest->getType(), Func, Instr, Addr)) { |
| 3835 Instr->setDeleted(); |
| 3836 Context.insert(InstLoad::create(Func, Dest, Mem)); |
| 3837 } |
| 3838 } |
3379 | 3839 |
3380 void TargetARM32::randomlyInsertNop(float Probability, | 3840 void TargetARM32::randomlyInsertNop(float Probability, |
3381 RandomNumberGenerator &RNG) { | 3841 RandomNumberGenerator &RNG) { |
3382 RandomNumberGeneratorWrapper RNGW(RNG); | 3842 RandomNumberGeneratorWrapper RNGW(RNG); |
3383 if (RNGW.getTrueWithProbability(Probability)) { | 3843 if (RNGW.getTrueWithProbability(Probability)) { |
3384 UnimplementedError(Func->getContext()->getFlags()); | 3844 UnimplementedError(Func->getContext()->getFlags()); |
3385 } | 3845 } |
3386 } | 3846 } |
3387 | 3847 |
3388 void TargetARM32::lowerPhi(const InstPhi * /*Inst*/) { | 3848 void TargetARM32::lowerPhi(const InstPhi * /*Inst*/) { |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3569 Variable *ValueHi = legalizeToReg(hiOperand(Value)); | 4029 Variable *ValueHi = legalizeToReg(hiOperand(Value)); |
3570 Variable *ValueLo = legalizeToReg(loOperand(Value)); | 4030 Variable *ValueLo = legalizeToReg(loOperand(Value)); |
3571 _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr))); | 4031 _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr))); |
3572 _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr))); | 4032 _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr))); |
3573 } else { | 4033 } else { |
3574 Variable *ValueR = legalizeToReg(Value); | 4034 Variable *ValueR = legalizeToReg(Value); |
3575 _str(ValueR, NewAddr); | 4035 _str(ValueR, NewAddr); |
3576 } | 4036 } |
3577 } | 4037 } |
3578 | 4038 |
3579 void TargetARM32::doAddressOptStore() {} | 4039 void TargetARM32::doAddressOptStore() { |
| 4040 Inst *Instr = Context.getCur(); |
| 4041 assert(llvm::isa<InstStore>(Instr)); |
| 4042 Operand *Src = Instr->getSrc(0); |
| 4043 Operand *Addr = Instr->getSrc(1); |
| 4044 if (OperandARM32Mem *Mem = |
| 4045 formAddressingMode(Src->getType(), Func, Instr, Addr)) { |
| 4046 Instr->setDeleted(); |
| 4047 Context.insert(InstStore::create(Func, Src, Mem)); |
| 4048 } |
| 4049 } |
3580 | 4050 |
3581 void TargetARM32::lowerSwitch(const InstSwitch *Inst) { | 4051 void TargetARM32::lowerSwitch(const InstSwitch *Inst) { |
3582 // This implements the most naive possible lowering. | 4052 // This implements the most naive possible lowering. |
3583 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default | 4053 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default |
3584 Operand *Src0 = Inst->getComparison(); | 4054 Operand *Src0 = Inst->getComparison(); |
3585 SizeT NumCases = Inst->getNumCases(); | 4055 SizeT NumCases = Inst->getNumCases(); |
3586 if (Src0->getType() == IceType_i64) { | 4056 if (Src0->getType() == IceType_i64) { |
3587 Src0 = legalizeUndef(Src0); | 4057 Src0 = legalizeUndef(Src0); |
3588 Variable *Src0Lo = legalizeToReg(loOperand(Src0)); | 4058 Variable *Src0Lo = legalizeToReg(loOperand(Src0)); |
3589 Variable *Src0Hi = legalizeToReg(hiOperand(Src0)); | 4059 Variable *Src0Hi = legalizeToReg(hiOperand(Src0)); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3666 } | 4136 } |
3667 } | 4137 } |
3668 } | 4138 } |
3669 } | 4139 } |
3670 | 4140 |
3671 // Go through the various types of operands: OperandARM32Mem, | 4141 // Go through the various types of operands: OperandARM32Mem, |
3672 // OperandARM32Flex, Constant, and Variable. Given the above assertion, if | 4142 // OperandARM32Flex, Constant, and Variable. Given the above assertion, if |
3673 // type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we | 4143 // type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we |
3674 // can always copy to a register. | 4144 // can always copy to a register. |
3675 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { | 4145 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { |
3676 static const struct { | |
3677 bool CanHaveOffset; | |
3678 bool CanHaveIndex; | |
3679 } MemTraits[] = { | |
3680 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr) \ | |
3681 { (ubits) > 0, rraddr } \ | |
3682 , | |
3683 ICETYPEARM32_TABLE | |
3684 #undef X | |
3685 }; | |
3686 // Before doing anything with a Mem operand, we need to ensure that the | 4146 // Before doing anything with a Mem operand, we need to ensure that the |
3687 // Base and Index components are in physical registers. | 4147 // Base and Index components are in physical registers. |
3688 Variable *Base = Mem->getBase(); | 4148 Variable *Base = Mem->getBase(); |
3689 Variable *Index = Mem->getIndex(); | 4149 Variable *Index = Mem->getIndex(); |
3690 ConstantInteger32 *Offset = Mem->getOffset(); | 4150 ConstantInteger32 *Offset = Mem->getOffset(); |
3691 assert(Index == nullptr || Offset == nullptr); | 4151 assert(Index == nullptr || Offset == nullptr); |
3692 Variable *RegBase = nullptr; | 4152 Variable *RegBase = nullptr; |
3693 Variable *RegIndex = nullptr; | 4153 Variable *RegIndex = nullptr; |
3694 if (Base) { | 4154 assert(Base); |
3695 RegBase = legalizeToReg(Base); | 4155 RegBase = legalizeToReg(Base); |
3696 } | 4156 bool InvalidImm = false; |
| 4157 assert(Ty < MemTraitsSize); |
3697 if (Index) { | 4158 if (Index) { |
| 4159 assert(Offset == nullptr); |
| 4160 assert(MemTraits[Ty].CanHaveIndex); |
3698 RegIndex = legalizeToReg(Index); | 4161 RegIndex = legalizeToReg(Index); |
3699 if (!MemTraits[Ty].CanHaveIndex) { | |
3700 Variable *T = makeReg(IceType_i32, getReservedTmpReg()); | |
3701 _add(T, RegBase, RegIndex); | |
3702 RegBase = T; | |
3703 RegIndex = nullptr; | |
3704 } | |
3705 } | 4162 } |
3706 if (Offset && Offset->getValue() != 0) { | 4163 if (Offset && Offset->getValue() != 0) { |
3707 static constexpr bool SignExt = false; | 4164 assert(Index == nullptr); |
3708 if (!MemTraits[Ty].CanHaveOffset || | 4165 static constexpr bool ZeroExt = false; |
3709 !OperandARM32Mem::canHoldOffset(Ty, SignExt, Offset->getValue())) { | 4166 assert(MemTraits[Ty].CanHaveImm); |
3710 Variable *T = legalizeToReg(Offset, getReservedTmpReg()); | 4167 if (!OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) { |
3711 _add(T, T, RegBase); | 4168 assert(RegBase->hasReg()); |
3712 RegBase = T; | 4169 assert(RegBase->getRegNum() == (int32_t)getFrameOrStackReg()); |
3713 Offset = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)); | 4170 // We are a bit more lenient with invalid immediate when accessing the |
| 4171 // stack here, and then rely on legalizeStackSlots() to fix things as |
| 4172 // appropriate. |
| 4173 InvalidImm = true; |
3714 } | 4174 } |
3715 } | 4175 } |
3716 | 4176 |
3717 // Create a new operand if there was a change. | 4177 // Create a new operand if there was a change. |
3718 if (Base != RegBase || Index != RegIndex) { | 4178 if (Base != RegBase || Index != RegIndex) { |
3719 // There is only a reg +/- reg or reg + imm form. | 4179 // There is only a reg +/- reg or reg + imm form. |
3720 // Figure out which to re-create. | 4180 // Figure out which to re-create. |
3721 if (RegBase && RegIndex) { | 4181 if (RegIndex) { |
3722 Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex, | 4182 Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex, |
3723 Mem->getShiftOp(), Mem->getShiftAmt(), | 4183 Mem->getShiftOp(), Mem->getShiftAmt(), |
3724 Mem->getAddrMode()); | 4184 Mem->getAddrMode()); |
3725 } else { | 4185 } else { |
3726 Mem = OperandARM32Mem::create(Func, Ty, RegBase, Offset, | 4186 Mem = OperandARM32Mem::create(Func, Ty, RegBase, Offset, |
3727 Mem->getAddrMode()); | 4187 Mem->getAddrMode()); |
3728 } | 4188 } |
3729 } | 4189 } |
3730 if (Allowed & Legal_Mem) { | 4190 if (Allowed & Legal_Mem) { |
3731 From = Mem; | 4191 From = Mem; |
3732 } else { | 4192 } else { |
3733 Variable *Reg = makeReg(Ty, RegNum); | 4193 Variable *Reg = makeReg(Ty, RegNum); |
3734 _ldr(Reg, Mem); | 4194 if (InvalidImm) { |
| 4195 // If Mem has an invalid immediate, we legalize it to a Reg using mov |
| 4196 // instead of ldr because legalizeStackSlots() will later kick in and |
| 4197 // fix the immediate for us. |
| 4198 _mov(Reg, Mem); |
| 4199 } else { |
| 4200 _ldr(Reg, Mem); |
| 4201 } |
| 4202 |
3735 From = Reg; | 4203 From = Reg; |
3736 } | 4204 } |
3737 return From; | 4205 return From; |
3738 } | 4206 } |
3739 | 4207 |
3740 if (auto *Flex = llvm::dyn_cast<OperandARM32Flex>(From)) { | 4208 if (auto *Flex = llvm::dyn_cast<OperandARM32Flex>(From)) { |
3741 if (!(Allowed & Legal_Flex)) { | 4209 if (!(Allowed & Legal_Flex)) { |
3742 if (auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Flex)) { | 4210 if (auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Flex)) { |
3743 if (FlexReg->getShiftOp() == OperandARM32::kNoShift) { | 4211 if (FlexReg->getShiftOp() == OperandARM32::kNoShift) { |
3744 From = FlexReg->getReg(); | 4212 From = FlexReg->getReg(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3797 Variable *Reg = makeReg(Ty, RegNum); | 4265 Variable *Reg = makeReg(Ty, RegNum); |
3798 _movw(Reg, C); | 4266 _movw(Reg, C); |
3799 _movt(Reg, C); | 4267 _movt(Reg, C); |
3800 return Reg; | 4268 return Reg; |
3801 } else { | 4269 } else { |
3802 assert(isScalarFloatingType(Ty)); | 4270 assert(isScalarFloatingType(Ty)); |
3803 // Load floats/doubles from literal pool. | 4271 // Load floats/doubles from literal pool. |
3804 // TODO(jvoung): Allow certain immediates to be encoded directly in an | 4272 // TODO(jvoung): Allow certain immediates to be encoded directly in an |
3805 // operand. See Table A7-18 of the ARM manual: "Floating-point modified | 4273 // operand. See Table A7-18 of the ARM manual: "Floating-point modified |
3806 // immediate constants". Or, for 32-bit floating point numbers, just | 4274 // immediate constants". Or, for 32-bit floating point numbers, just |
3807 // encode the raw bits into a movw/movt pair to GPR, and vmov to an SREG, | 4275 // encode the raw bits into a movw/movt pair to GPR, and vmov to an SREG |
3808 // instead of using a movw/movt pair to get the const-pool address then | 4276 // instead of using a movw/movt pair to get the const-pool address then |
3809 // loading to SREG. | 4277 // loading to SREG. |
3810 std::string Buffer; | 4278 std::string Buffer; |
3811 llvm::raw_string_ostream StrBuf(Buffer); | 4279 llvm::raw_string_ostream StrBuf(Buffer); |
3812 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); | 4280 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); |
3813 llvm::cast<Constant>(From)->setShouldBePooled(true); | 4281 llvm::cast<Constant>(From)->setShouldBePooled(true); |
3814 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); | 4282 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); |
3815 Variable *BaseReg = makeReg(getPointerType()); | 4283 Variable *BaseReg = makeReg(getPointerType()); |
3816 _movw(BaseReg, Offset); | 4284 _movw(BaseReg, Offset); |
3817 _movt(BaseReg, Offset); | 4285 _movt(BaseReg, Offset); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3867 } | 4335 } |
3868 | 4336 |
3869 OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) { | 4337 OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) { |
3870 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); | 4338 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); |
3871 // It may be the case that address mode optimization already creates an | 4339 // It may be the case that address mode optimization already creates an |
3872 // OperandARM32Mem, so in that case it wouldn't need another level of | 4340 // OperandARM32Mem, so in that case it wouldn't need another level of |
3873 // transformation. | 4341 // transformation. |
3874 if (Mem) { | 4342 if (Mem) { |
3875 return llvm::cast<OperandARM32Mem>(legalize(Mem)); | 4343 return llvm::cast<OperandARM32Mem>(legalize(Mem)); |
3876 } | 4344 } |
3877 // If we didn't do address mode optimization, then we only have a base/offset | 4345 // If we didn't do address mode optimization, then we only have a |
3878 // to work with. ARM always requires a base register, so just use that to | 4346 // base/offset to work with. ARM always requires a base register, so |
3879 // hold the operand. | 4347 // just use that to hold the operand. |
3880 Variable *Base = legalizeToReg(Operand); | 4348 Variable *Base = legalizeToReg(Operand); |
3881 return OperandARM32Mem::create( | 4349 return OperandARM32Mem::create( |
3882 Func, Ty, Base, | 4350 Func, Ty, Base, |
3883 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); | 4351 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); |
3884 } | 4352 } |
3885 | 4353 |
3886 Variable64On32 *TargetARM32::makeI64RegPair() { | 4354 Variable64On32 *TargetARM32::makeI64RegPair() { |
3887 Variable64On32 *Reg = | 4355 Variable64On32 *Reg = |
3888 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); | 4356 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
3889 Reg->setMustHaveReg(); | 4357 Reg->setMustHaveReg(); |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4088 void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars, | 4556 void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars, |
4089 const IceString &SectionSuffix) { | 4557 const IceString &SectionSuffix) { |
4090 switch (Ctx->getFlags().getOutFileType()) { | 4558 switch (Ctx->getFlags().getOutFileType()) { |
4091 case FT_Elf: { | 4559 case FT_Elf: { |
4092 ELFObjectWriter *Writer = Ctx->getObjectWriter(); | 4560 ELFObjectWriter *Writer = Ctx->getObjectWriter(); |
4093 Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix); | 4561 Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix); |
4094 } break; | 4562 } break; |
4095 case FT_Asm: | 4563 case FT_Asm: |
4096 case FT_Iasm: { | 4564 case FT_Iasm: { |
4097 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); | 4565 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); |
4098 OstreamLocker L(Ctx); | 4566 OstreamLocker _(Ctx); |
4099 for (const VariableDeclaration *Var : Vars) { | 4567 for (const VariableDeclaration *Var : Vars) { |
4100 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { | 4568 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { |
4101 emitGlobal(*Var, SectionSuffix); | 4569 emitGlobal(*Var, SectionSuffix); |
4102 } | 4570 } |
4103 } | 4571 } |
4104 } break; | 4572 } break; |
4105 } | 4573 } |
4106 } | 4574 } |
4107 | 4575 |
4108 namespace { | 4576 namespace { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4191 | 4659 |
4192 void TargetDataARM32::lowerConstants() { | 4660 void TargetDataARM32::lowerConstants() { |
4193 if (Ctx->getFlags().getDisableTranslation()) | 4661 if (Ctx->getFlags().getDisableTranslation()) |
4194 return; | 4662 return; |
4195 switch (Ctx->getFlags().getOutFileType()) { | 4663 switch (Ctx->getFlags().getOutFileType()) { |
4196 case FT_Elf: | 4664 case FT_Elf: |
4197 UnimplementedError(Ctx->getFlags()); | 4665 UnimplementedError(Ctx->getFlags()); |
4198 break; | 4666 break; |
4199 case FT_Asm: | 4667 case FT_Asm: |
4200 case FT_Iasm: { | 4668 case FT_Iasm: { |
4201 OstreamLocker L(Ctx); | 4669 OstreamLocker _(Ctx); |
4202 emitConstantPool<float>(Ctx); | 4670 emitConstantPool<float>(Ctx); |
4203 emitConstantPool<double>(Ctx); | 4671 emitConstantPool<double>(Ctx); |
4204 break; | 4672 break; |
4205 } | 4673 } |
4206 } | 4674 } |
4207 } | 4675 } |
4208 | 4676 |
4209 void TargetDataARM32::lowerJumpTables() { | 4677 void TargetDataARM32::lowerJumpTables() { |
4210 if (Ctx->getFlags().getDisableTranslation()) | 4678 if (Ctx->getFlags().getDisableTranslation()) |
4211 return; | 4679 return; |
4212 switch (Ctx->getFlags().getOutFileType()) { | 4680 switch (Ctx->getFlags().getOutFileType()) { |
4213 case FT_Elf: | 4681 case FT_Elf: |
4214 UnimplementedError(Ctx->getFlags()); | 4682 UnimplementedError(Ctx->getFlags()); |
4215 break; | 4683 break; |
4216 case FT_Asm: | 4684 case FT_Asm: |
4217 // Already emitted from Cfg | 4685 // Already emitted from Cfg |
4218 break; | 4686 break; |
4219 case FT_Iasm: { | 4687 case FT_Iasm: { |
4220 // TODO(kschimpf): Fill this in when we get more information. | 4688 // TODO(kschimpf): Fill this in when we get more information. |
4221 break; | 4689 break; |
4222 } | 4690 } |
4223 } | 4691 } |
4224 } | 4692 } |
4225 | 4693 |
4226 TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx) | 4694 TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx) |
4227 : TargetHeaderLowering(Ctx), CPUFeatures(Ctx->getFlags()) {} | 4695 : TargetHeaderLowering(Ctx), CPUFeatures(Ctx->getFlags()) {} |
4228 | 4696 |
4229 void TargetHeaderARM32::lower() { | 4697 void TargetHeaderARM32::lower() { |
4230 OstreamLocker L(Ctx); | 4698 OstreamLocker _(Ctx); |
4231 Ostream &Str = Ctx->getStrEmit(); | 4699 Ostream &Str = Ctx->getStrEmit(); |
4232 Str << ".syntax unified\n"; | 4700 Str << ".syntax unified\n"; |
4233 // Emit build attributes in format: .eabi_attribute TAG, VALUE. See Sec. 2 of | 4701 // Emit build attributes in format: .eabi_attribute TAG, VALUE. See Sec. 2 of |
4234 // "Addenda to, and Errata in the ABI for the ARM architecture" | 4702 // "Addenda to, and Errata in the ABI for the ARM architecture" |
4235 // http://infocenter.arm.com | 4703 // http://infocenter.arm.com |
4236 // /help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf | 4704 // /help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf |
4237 // | 4705 // |
4238 // Tag_conformance should be be emitted first in a file-scope sub-subsection | 4706 // Tag_conformance should be be emitted first in a file-scope sub-subsection |
4239 // of the first public subsection of the attributes. | 4707 // of the first public subsection of the attributes. |
4240 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n"; | 4708 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n"; |
(...skipping 29 matching lines...) Expand all Loading... |
4270 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 4738 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
4271 // However, for compatibility with current NaCl LLVM, don't claim that. | 4739 // However, for compatibility with current NaCl LLVM, don't claim that. |
4272 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 4740 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
4273 } | 4741 } |
4274 | 4742 |
4275 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; | 4743 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; |
4276 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; | 4744 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; |
4277 llvm::SmallBitVector TargetARM32::ScratchRegs; | 4745 llvm::SmallBitVector TargetARM32::ScratchRegs; |
4278 | 4746 |
4279 } // end of namespace Ice | 4747 } // end of namespace Ice |
OLD | NEW |